Stubbing and Mocking Static Methods with PHPUnit
Consider the class
Foo
:
<?php class Foo { public static function doSomething() { return static::helper(); } public static function helper() { return 'foo'; } } ?>
To test the static helper() function with PHPUnit, you can write you test like that:
<?php class FooTest extends PHPUnit_Framework_TestCase { public function testDoSomething() { $class = $this->getMockClass( 'Foo', /* name of class to mock */ array('helper') /* list of methods to mock */ ); $class::staticExpects($this->any()) ->method('helper') ->will($this->returnValue('bar')); $this->assertEquals( 'bar', $class::doSomething() ); } } ?>The new
staticExpects()
method works similar to the non-static expects()
variant. This approach only works for the stubbing and mocking of static method calls where caller and callee are in the same class. This is because static methods are death to testability:"Unit-Testing needs seams, seams is where we prevent the execution of normal code path and is how we achieve isolation of the class under test. Seams work through polymorphism, we override/implement class/interface and then wire the class under test differently in order to take control of the execution flow. With static methods there is nothing to override. Yes, static methods are easy to call, but if the static method calls another static method there is no way to override the called method dependency."Update: Above feature has been dropped from PHPUnit 3.7 https://github.com/sebastianbergmann/phpunit-documentation/issues/77
Few best practices
One Assertion per Test
Few tips and best practices on how to write your unit tests efficiently. One of the best advises would be "one test = one assertion". You may think that cutting corners may be a good idea; well, think again. Here's a little test scenario - you need to test if the function returns string. You name this function as "testIfFunctionReturnsString". And while asserting string, you may be tempted to also do other assertions - why not test for that as well?Consider following test:
<?php public function testIfFunctionReturnsString(){ $string = "Hello World"; $this->assertGreaterThan(0,strlen($string)); $this->assertContains("99",$string); } ?>
In this case you are testing string length and also if string contains "99". Second assertion will fail, yet the result can be deceptive and might cause confusion what caused the error.
Be descriptive about what you are testing
<?php class Money extends PHPUnit_Framework_TestCase { public function testCanBeNegated() { $a = new Money(); $b = $a->Negate(1); $this->assertEquals(-1, $b->getAmount()); } } ?>
vendor/bin/phpunit
--stderr --testdox tests
Running this will print nice, human readable output which is easy to understand
PHPUnit 3.7.24 by Sebastian Bergmann. Money [x] Can be negated
Conclusion
Start testing your PHP applications today if you haven't already.PHPUnit |
Comments
Post a Comment