为什么不嘲笑日志记录调用?

So I am not sure what I am doing wrong but:

class Details {

    public function details($href) {
        $client = new Client();
        $eveLog = new EveLogHandler();

        $response = $client->request('GET', $href);
        $eveLog->requestLog($response, 'eveonline_item_details.log');

        if ($response->getStatusCode() === 200) {
            return json_decode($response->getBody()->getContents());
        }

        return false;
    }
}

I want to mock this: $eveLog->requestLog($response, 'eveonline_item_details.log');

So I wrote a test:

class DetailsTest extends \PHPUnit_Framework_TestCase {

    public function getLogMock() {
        return $this->getMockBuilder('EveOnline\Logging\EveLogHandler')
             ->setMethods(['requestLog'])
             ->getMock();
    }

    public function testDetailsDoesNotReturnFalse() {

        $details = new EveOnline\Items\Details();

        $logger = $this->getLogMock();
        $logger->expects($this->exactly(1))
            ->method('requestLog')
            ->with('request', 'request.log');

        $response = $details->details('http://example.com');

        $this->assertNotFalse($response);
    }
}

Accept it doesnt mock the method call, instead it freaks out with an error:

1) DetailsTest::testDetailsDoesNotReturnFalse
Error: Call to undefined function EveOnline\Logging\storage_path()

Now this method: storage_path is a laravel method and since this library is out side of laravel, for development purposes, the method doesn't exist, hence me trying to mock the call to: $eveLog->requestLog($response, 'eveonline_item_details.log');

Two questions arise from this:

  1. First of all why doesn't my test pick up on the fact that I have mocked the method call?
  2. When it coms time to test this particular method how do you mock global functions? Laravel has a few of them and I'll need mock out the storage_path method.

Ideas?

update

It should be known that this class gets turned into a laravel facade via a provider class and a facade class that both get registered with laravel allowing me to do something like

EveDetails::details()

For example. Learn more here https://laravel.com/docs/5.1/facades

I can post the facade and provider class of that will help.

The only reason the class is instantiated in my ear is because this particular component is being built as a separate installable component of laravel.

Your method Details::details() doesn't know that $eveLog should be an instance of your mock instead of class EveLogHandler. You have to inject the instance of your logger by using dependency injection.

The simpliest way to do this is to put it to the constructor:

class Details {

    private $eveLog;

    public function __construct($eveLog) {
        $this->eveLog = $eveLog;
    }

    public function details($href) {
        $client = new Client();

        $response = $client->request('GET', $href);
        $this->eveLog->requestLog($response, 'eveonline_item_details.log');

        if ($response->getStatusCode() === 200) {
            return json_decode($response->getBody()->getContents());
        }

        return false;
    }
}

In your production code you'll have to call:

$details = new EveOnline\Items\Details(new EveLogHandler());

to inject the real Eventlogger (an instance of class EveLogHandler) to the instance of class Details.

In your TestCase you'll now have inject your mock:

$logger = $this->getLogMock();
$logger->expects($this->exactly(1))
       ->method('requestLog')
       ->with('request', 'request.log');

$details = new EveOnline\Items\Details($logger);