1

I'm wondering how to go about testing this. Say I have a getter method, and I change the value in the process of a method. Here's a simple example:

public function foo($model)
{
  var_dump($model->state());
  $model->state('saved');
  var_dump($model->state());
}

I mock the model like so:

$model = $this->getMock('Model');
$model->expects($this->any))
  ->method('state')
  ->will($this->returnValue('new'));

How should I setup the mock so that the second call returns a different value (saved)?

2 Answers 2

3
$model = $this->getMock('Model');
$model->expects($this->at(0))
  ->method('state')
  ->will($this->returnValue('new'));
$model->expects($this->at(1))
  ->method('state')
  ->will($this->returnValue('saved'));
$model->expects($this->exactly(2))
  ->method('state');

http://www.phpunit.de/manual/3.6/en/test-doubles.html#test-doubles.mock-objects

Plus you can additionally check with with() that the parameter passed equals to saved

->with($this->equalTo('saved'))

PS: this will work for

public function foo($model)
{
  var_dump($model->state());
  var_dump($model->state('saved'));
}

For your code you need to set up 3 mock calls, not 2

Sign up to request clarification or add additional context in comments.

2 Comments

IIRC equalTo is the default if you pass a bare value so you can use with('saved'). At least I hope that's the case because we do that a lot. :)
@David Harkness: yep, I also use it in 50/50, because hadn't time yet to sit and check the real difference ;-)
3

With Mockery, which integrates with PHPUnit but is a far superior mocking library, you would write it like this:

$model = m::mock('model');
$model->shouldReceive('state')->andReturn($returnValue, $differentReturnValue);

It is obvious how much more beautiful the Mockery API is. It's an ode to readable code. It reads like text...

model should receive state and return values

You can add a constraint that the method has to be called exactly twice like so:

$model->shouldReceive('state')->twice()->andReturn($value, $differentValue);

If you want to pass arguments, it looks like this:

$model->shouldReceive('state')->withNoArgs()->andReturn($value)->once();
$model->shouldReceive('state')->with('saved')->andReturn($differentValue)->once();

2 Comments

Just curious - how to specify that in first call there should be no arguments to state passed and that in second call the argument should be equal to saved?
PHPUnit tends to use methods that accept arguments created using methods on the test case, requiring a lot of $this->. I wrote simple helper methods to avoid this to make the API read more like English, similar to what Mockery does, e.g. $mock->expect('foo')->once()->willReturn('bar'). The end result is the same, but it improves readibility.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.