Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock in PHPUnit - multiple configuration of the same method with different arguments

Is it possible to configure PHPUnit mock in this way?

$context = $this->getMockBuilder('Context')    ->getMock();  $context->expects($this->any())    ->method('offsetGet')    ->with('Matcher')    ->will($this->returnValue(new Matcher()));  $context->expects($this->any())    ->method('offsetGet')    ->with('Logger')    ->will($this->returnValue(new Logger())); 

I use PHPUnit 3.5.10 and it fails when I ask for Matcher because it expects "Logger" argument. It is like the second expectation is rewriting the first one, but when I dump the mock, everything looks ok.

like image 536
Václav Novotný Avatar asked Mar 30 '11 09:03

Václav Novotný


People also ask

Which method is used to create a mock with PHPUnit?

PHPUnit provides methods that are used to automatically create objects that will replace the original object in our test. createMock($type) and getMockBuilder($type) methods are used to create mock object. The createMock method immediately returns a mock object of the specified type.

What is .setup in mock?

Setup method is used to set expectations on the mock object For example: mock. Setup(foo => foo. DoSomething("ping")). Returns(true);

What is PHPUnit testing?

PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit architecture for unit testing frameworks that originated with SUnit and became popular with JUnit. PHPUnit was created by Sebastian Bergmann and its development is hosted on GitHub.

What is the use of PHPUnit?

PHPUnit is a framework independent library for unit testing PHP. Unit testing is a method by which small units of code are tested against expected results. Traditional testing tests an app as a whole meaning that individual components rarely get tested alone.


1 Answers

Sadly this is not possible with the default PHPUnit Mock API.

I can see two options that can get you close to something like this:

Using ->at($x)

$context = $this->getMockBuilder('Context')    ->getMock();  $context->expects($this->at(0))    ->method('offsetGet')    ->with('Matcher')    ->will($this->returnValue(new Matcher()));  $context->expects($this->at(1))    ->method('offsetGet')    ->with('Logger')    ->will($this->returnValue(new Logger())); 

This will work fine but you are testing more than you should (mainly that it gets called with matcher first, and that is an implementation detail).

Also this will fail if you have more than one call to each of of the functions!


Accepting both parameters and using returnCallBack

This is more work but works nicer since you don't depend on the order of the calls:

Working example:

<?php  class FooTest extends PHPUnit_Framework_TestCase {       public function testX() {          $context = $this->getMockBuilder('Context')            ->getMock();          $context->expects($this->exactly(2))            ->method('offsetGet')            ->with($this->logicalOr(                      $this->equalTo('Matcher'),                       $this->equalTo('Logger')             ))            ->will($this->returnCallback(                 function($param) {                     var_dump(func_get_args());                     // The first arg will be Matcher or Logger                     // so something like "return new $param" should work here                 }            ));          $context->offsetGet("Matcher");         $context->offsetGet("Logger");       }  }  class Context {      public function offsetGet() { echo "org"; } } 

This will output:

/* $ phpunit footest.php PHPUnit 3.5.11 by Sebastian Bergmann.  array(1) {   [0]=>   string(7) "Matcher" } array(1) {   [0]=>   string(6) "Logger" } . Time: 0 seconds, Memory: 3.00Mb  OK (1 test, 1 assertion) 

I've used $this->exactly(2) in the matcher to show that this does also work with counting the invocations. If you don't need that swapping it out for $this->any() will, of course, work.

like image 86
edorian Avatar answered Sep 24 '22 00:09

edorian