我怎样才能让PHPUnit MockObjects根据参数返回不同的值?

我有一个PHPUnit模拟对象返回'return value'不pipe它的参数:

 // From inside a test... $mock = $this->getMock('myObject', 'methodToMock'); $mock->expects($this->any)) ->method('methodToMock') ->will($this->returnValue('return value')); 

我希望能够做的是返回一个不同的值基于传递给模拟方法的参数。 我试过类似的东西:

 $mock = $this->getMock('myObject', 'methodToMock'); // methodToMock('one') $mock->expects($this->any)) ->method('methodToMock') ->with($this->equalTo('one')) ->will($this->returnValue('method called with argument "one"')); // methodToMock('two') $mock->expects($this->any)) ->method('methodToMock') ->with($this->equalTo('two')) ->will($this->returnValue('method called with argument "two"')); 

但是这会导致PHPUnit投诉,如果模拟不是用参数'two'调用'two' ,所以我假设methodToMock('two')的定义覆盖了第一个的定义。

所以我的问题是:有什么办法让一个PHPUnit模拟对象返回基于它的参数不同的值? 如果是的话,怎么样?

使用callback。 例如(直接从PHPUnit文档):

 <?php class StubTest extends PHPUnit_Framework_TestCase { public function testReturnCallbackStub() { $stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnCallback('callback')); // $stub->doSomething() returns callback(...) } } function callback() { $args = func_get_args(); // ... } ?> 

在callback()中做任何你想要的处理,并根据你的$ args返回结果。

从最新的phpUnit文档:“有时候stubbed方法应该根据预定义的参数列表返回不同的值,可以使用returnValueMap()来创build一个将参数与相应的返回值关联的映射。

 $mock->expects($this->any()) ->method('getConfigValue') ->will( $this->returnValueMap( array( array('firstparam', 'secondparam', 'retval'), array('modes', 'foo', array('Array', 'of', 'modes')) ) ) ); 

我有一个类似的问题(虽然略有不同…我不需要基于参数不同的返回值,但不得不testing,以确保2套parameter passing给相同的function)。 我偶然发现了这样的事情:

 $mock = $this->getMock(); $mock->expects($this->at(0)) ->method('foo') ->with(...) ->will($this->returnValue(...)); $mock->expects($this->at(1)) ->method('foo') ->with(...) ->will($this->returnValue(...)); 

这并不完美,因为它要求2次调用foo()的次序是已知的,但实际上这可能不是糟糕。

你可能会想要做一个OOP的callback:

 <?php class StubTest extends PHPUnit_Framework_TestCase { public function testReturnAction() { $object = $this->getMock('class_name', array('method_to_mock')); $object->expects($this->any()) ->method('method_to_mock') ->will($this->returnCallback(array($this, 'returnCallback')); $object->returnAction('param1'); // assert what param1 should return here $object->returnAction('param2'); // assert what param2 should return here } public function returnCallback() { $args = func_get_args(); // process $args[0] here and return the data you want to mock return 'The parameter was ' . $args[0]; } } ?> 

这不完全是你问的,但在某些情况下,它可以帮助:

 $mock->expects( $this->any() ) ) ->method( 'methodToMock' ) ->will( $this->onConsecutiveCalls( 'one', 'two' ) ); 

onConccutiveCalls – 以指定的顺序返回一个值列表

你也可以返回参数如下:

 $stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnArgument(0)); 

传递两个级别的数组,其中每个元素是一个数组:

  • 首先是方法参数,最less是返回值。

例:

 ->willReturnMap([ ['firstArg', 'secondArg', 'returnValue'] ]) 

你的意思是这样吗?

 public function TestSomeCondition($condition){ $mockObj = $this->getMockObject(); $mockObj->setReturnValue('yourMethod',$condition); } 

我有一个类似的问题,我也无法工作(关于PHPUnit有惊人的信息很less)。 就我而言,我只是将每个testing单独testing – 已知input和已知输出。 我意识到,我不需要做一个万能的模拟对象,我只需要一个具体的testing,因此我分开了testing,并可以单独testing我的代码的各个方面单元。 我不确定这是否适用于您,但这是您需要testing的。

 $this->BusinessMock = $this->createMock('AppBundle\Entity\Business'); public function testBusiness() { /* onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called . */ $this->BusinessMock ->method('getEmployees') ->will($this->onConsecutiveCalls( $this->returnArgument(0), $this->returnValue('employee') ) ); // first call $this->assertInstanceOf( //$this->returnArgument(0), 'argument', $this->BusinessMock->getEmployees() ); // second call $this->assertEquals('employee',$this->BusinessMock->getEmployees()) //$this->returnValue('employee'), } 

试试:

 ->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));