1

So I have an object which I am mocking and it has methods that are used for sending emails. I have gone from a static class over to a concrete class because I was having issues testing the static class with Mockery.

However I am now finding that when an eloquent model is saved it throws an event which fires off a listener. This listener is what is responsible for kicking off the call to the mock objects method.

I have found that when I do something like the following it works.

$model = factory(MyClass::class)->make();
$model->property = 'value';
$model->save()
$this->mailer->shouldHaveReceived('methodName')->with($arg1, $arg2, $arg3);

It will fail every time complaining that the method does not exist on the mock object, the worst part is if I go into my listener where the mock object method is called and I do something like this

echo '<pre>'.print_r(get_class_methods($this->mailer), true).'</pre>'; exit;

it shows that the method is in-fact in the array of methods returned from get_class_methods.

Now here is the kicker. Everything works perfectly and the test passes without any errors if I do the following:

$this->mailer->shouldReceive('methodName');
$model = factory(MyClass::class)->make();
$model->property = 'value';
$model->save()

Now I have been reading the Mockery Gotchas and it would appear that if my class was calling a method that truly didn't exist on the object via ___call then this error would be expected.

However my mailer class is NOT extending any other class that would have a __call method nor does it have that method defined on the class.

However as you may or may not know Eloquent Models do in-fact use the magic ___call method. However I am NOT mocking the model with Mockery, I am using factory models in Laravel but I am also not checking the model object for the method call, I am checking my concrete mailer class for the method call.

Anyone know why I might be getting this behavior from Mockery?

I am creating my mock object in Laravel 5.2 with the following code

public function mock($class)
{
    $mock = Mockery::mock($class);
    $this->app->instance($class, $mock);
    return $mock;
}

$this->mailer = $this->mock('Namespace\Classname');
Scott Weldon
  • 9,673
  • 6
  • 48
  • 67
Joseph Crawford
  • 1,470
  • 1
  • 15
  • 29

1 Answers1

0

How are you creating $this->mailer? In order to be able to use the spy functionality ->shouldHaveReceived, you need to have invoked Mockery::spy($className) or called the shouldIgnoreMissing method after creating the test double with Mockery::mock($className).

Dave Marshall
  • 7,367
  • 4
  • 22
  • 15
  • I have updated my post above to show how I am creating the mock object, though I have not seen anything regarding the spy method while researching this issue I will have to look into that. I haven't seen anything other than what I have posted above (edited) meaning to add the mock to the laravel application via the instance method. – Joseph Crawford Mar 24 '16 at 22:47
  • The problem is that the method does exist on the mock object and it says that it does not. – Joseph Crawford Mar 25 '16 at 12:51