1
votes

I am beginning to write tests using Laravel 4.2, PHPUnit, and Mockery.

How can I assert that a Mock Facade was called/run by the Controller that I am testing?

For example, I've got the following Mockery for Queue. My controller doesn't return anything that has to do with the Queue::push(), so is there a way I can assert that it triggered Queue::push()?

Queue::shouldReceive('push')->once();
Queue::shouldReceive('connected')->once();

If I comment out the Queue::push() in my controller, the Queue::shouldReceive throws an exception:

Mockery\Exception\InvalidCountException: Method push() from Mockery_0_Illuminate_Queue_QueueManager should be called exactly 1 times but called 0 times.

Is the only way to assert that the Mock Facade ran is to do something like the following?

    $queuepushran = false;
    try {
        Queue::shouldReceive('push')->once();
        Queue::shouldReceive('connected')->once();
        $queuepushran = true;           
    } catch (\Mockery\Exception\InvalidCountException $e) {
        //Queue threw an exception
        $queuepushran = false;
    }
    $this->assertTrue($queuepushran);
1

1 Answers

2
votes

You're on the right track with using mock objects and expectations to test this, but this isn't quite how mocks should be used. Your code snippet seems to be missing actually calling the controller, so it's hard to tell exactly what's going on, but I'll just run over a full example.

You want to test that when your controller method runs, the Queue facade's push() and connected() methods are called once each. What we want to do is use Laravel's cool facade functionality to replace the real QueueManager class behind the Queue facade with a mock one, that way when the controller calls Queue::push(..), it will be calling our mock object instead.

So, lets start building the test:

public function testSomeControllerMethodCallsTheQueue()
{
    Queue::shouldReceive('push')->once();
    Queue::shouldReceive('connected')->once();
}

We've now swapped out the real QueueManager for our mock one, and set up how we expect them to be called. Since each test should only be doing one thing, we've now done all we need to do to 'arrange' the test.

Next, we need to 'act' by calling the controller.

public function testSomeControllerMethodCallsTheQueue()
{
    Queue::shouldReceive('push')->once();
    Queue::shouldReceive('connected')->once();

    $this->action('GET', 'YourController@method');
}

The last step is to 'assert', but we don't actually need to do anything. If our Mockery expectations are met, the test will complete and go green. If our Mockery expectations are not met, an exception will be thrown and the test will go red. The exceptions that Mockery throws are intended to be what fails your test, you don't need to do assertions like when comparing the return value or response with what you expect -- Mockery handles all that.