Mocking models with a relationship in Laravel
Asked Answered
F

3

2

I'm attempting to create a Mockery of CustomObject then chain the retrieval of OtherObject onto it using something identical to

$this->CustomObject->with('OtherObject')->get();

I can't seem to figure out how to mock this ->get() at the end there. I'm mocking both of those models in my constructor method ['Eloquent', 'OtherObject', 'CustomObject']. If I remove the ->get() everything runs smoothly and my tests pass (aside from the php errors the view is then giving me, but those don't matter if the test is working correctly).

What I currently have is this:

$this->mock->shouldReceive('with')->once()->with('OtherObject');
$this->app->instance('CustomObject', $this->mock);

What should I be doing to mock this?

Edit: I have specifically attempted ->andReturn($this->mock) which only tells me that on the mocked object there is no get method.

Figurine answered 3/12, 2013 at 20:48 Comment(0)
A
2

You must return an instance of your mock to make the next chaining call (->get()) to work

$this->mock
     ->shouldReceive('with')
     ->once()
     ->with('OtherObject')
     ->andReturn($this->mock);
Angarsk answered 3/12, 2013 at 21:5 Comment(2)
I had tried specifically that and it still says that I cannot use the public member get on a non-object.Figurine
I don't recall what my issue was exactly at this point but your method is most certainly correct.Figurine
W
1

You can use Mockery::self() to define chained expectations with arguments.

$this->mock->shouldReceive('with')
    ->once()->with('OtherObject')
    ->andReturn(m::self())->getMock()
    ->shouldReceive('get')->once()
    ->andReturn($arrayOfMocks);

In some cases you may need to split it up into two mocks:

$mockQuery = m::mock();
$this->mock->shouldReceive('with')
    ->once()->with('OtherObject')
    ->andReturn($mockQuery);
$mockQuery->shouldReceive('get')->once()
    ->andReturn($arrayOfMocks);
Westfahl answered 3/1, 2014 at 11:17 Comment(0)
F
0

It looks like I have it. It seems that the previous answer and my attempts were very close. The largest issue with using these is that a method is being called on the return object. If this isn't the best way to do this, I hope someone will correct me though.

$other_object = Mockery::mock('OtherObject');
$other_object->shouldReceive('get')->once()->andReturn(new OtherObject);

$this->mock->shouldReceive('with')
           ->once()
           ->with('OtherObject')
           ->andReturn($other_object);

$this->app->instance('CustomObject', $this->mock);

and removing `OtherObject' from the constructor method.

Figurine answered 4/12, 2013 at 6:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.