phpunit - #covers tag not working - php

Maybe I missed out on a detail, but I wrote a small test case for a singleton _clone method yet it is not showing up as tested in the code coverage report.
/**
* #covers ErrorHandling::__clone
*/
public function test__cloneNotCloneable(){
$class = new ReflectionClass('ErrorHandling');
$method = $class->getMethod('__clone');
self::assertTrue($method->isFinal(), '__clone method is not final.');
self::assertTrue($method->isPrivate(), '__clone method is not private.');
}
The __clone method is the usual private/final __clone() of a regular (evil) singleton.
/**
* Define __clone as final and private to dissallow cloning.
*/
private final function __clone(){}
I know it's probably overkill testing for this, but the code-coverage report is sort of the graphical representation of a job 'well done'. Is there a way to have this method marked as covered in the code coverage report?

The #covers tag tells PHPUnit that you intend to test the named method; it does not mark the method as having been tested. Since you cannot call the method, Xdebug won't tell PHPUnit that its code has been executed, and it will never be covered in your report.
Your best bet is to tell PHPUnit to ignore the method in the report by using the #codeCoverageIgnore docblock tag.
/**
* Define __clone as final and private to dissallow cloning.
*
* #codeCoverageIgnore
*/
private final function __clone() { }
You can ignore any range of lines by enclosing them in a pair of one-line start/stop comments.
// #codeCoverageIgnoreStart
private final function __clone() { }
// #codeCoverageIgnoreEnd
Finally, you can ignore a single line by adding a one-line comment to it.
private final function __clone() { } // #codeCoverageIgnore

Related

Calculate code coverage on phpunit test classes

We are using phpunit to unit-test our classes like this
namespace VendorName/SystemName {
final class TestableClass { /** ... */ }
}
namespace VendorName/SystemName/Tests {
/**
* #group unit
* #covers /VendorName/SystemName/TestableClass
*/
final class TestableClassTest extends TestCase { /** ... */ }
}
When we run these test the TestableClass get covered correctly, but we also want to see, whether every line of code in TestableClassTest was actually exectued, as we deal with dead code sometimes like
/**
* #expectedException /InvalidArgumentException
*/
public function testSomeMethodThrowsException(): void
{
// do some arrangement
// call the tested method
$testable->someMethod();
// do some post-call assertions
self::assertBar($baz);
self::assertFoo($baz);
// lines above are actually dead code
// if test goes right and throws exception
}
So we wan't to grab coverage statistics for our tests also.
The straightforward way is to add #covers /VendorName/SystemName/Tests/TestableClassTest to each test class, but this requires a lot of manual work.
Is there a correct way to automatically get test cases coverage (maybe listener or config or other phpunit hacks)

Using #covers for a class

I am using php for testing my code. Here is an example:
/**
* #covers Calculator::
*/
class CalculatorTest extends PHPUnit_Framework_TestCase {
protected function setUp() { /* ... */ }
/**
* #covers Calculator::add
*/
public function testAddTwoIntegers() { /* ... */ }
/**
* #covers Calculator::multiply
*/
public function testMultiplyTwoIntegers() { /* ... */ }
}
However, my code is complicated and I want to get rid of #covers over individual test methods. How does php treat the following class when generating coverage reports:
/**
* #covers Calculator
*/
class CalculatorTest extends PHPUnit_Framework_TestCase {
protected function setUp() { /* ... */ }
public function testAddTwoIntegers() { /* ... */ }
public function testMultiplyTwoIntegers() { /* ... */ }
}
Notice that the #covers annotation over a class is still there but I have removed it from every method.
I am able to get coverage reports using this approach too but I have not seen an example of it anywhere, so I want to know if this is not a correct use.
Code Coverage Report:
2016-01-18 08:57:50
Summary:
Classes: 17.67% (56/317)
Methods: 0.33% (5/1520)
Lines: 0.60% (109/18094)
Class1:
Methods: 66.67% ( 2/ 3) Lines: 95.45% ( 21/ 22)
Class2:
Methods: 50.00% ( 3/ 6) Lines: 96.70% ( 88/ 91)
Indeed, setting the classname without the method name is the recommended #covers syntax.
Documentation here:
https://phpunit.readthedocs.io/en/8.5/annotations.html#covers
Annotation
#covers ClassName::methodName (not recommended)
#covers ClassName (recommended)
#covers ClassName<extended> (not recommended)
#covers ClassName::<public> (not recommended)
#covers ClassName::<protected> (not recommended)
#covers ClassName::<private> (not recommended)
#covers ClassName::<!public> (not recommended)
#covers ClassName::<!protected> (not recommended)
#covers ClassName::<!private> (not recommended)
#covers ::functionName (recommended)
When you ask:
How does php treat the following class when generating coverage reports
The answer is: Every line of the class mentioned in #covers executed during "any" of the tests in that TestCase will compute a +1 in the execution.
If you do real TDD and start first by writing the test, then writing the class, this is a perfect approach. Some of your lines in your public methods with branches will count 2 or more executions, and probably the lines inside each of the branches will count 1 execution.
Private methods will also count +n executions, while you won't write named tests for those methods, they will be called as a result of being helpers to the public methods.
When you say:
but I have not seen an example of it anywhere
I can tell that 90% of our tests use a #covers MyNiceClass annotation without specifying any method.
If you start by the test first, you normally won't mess up things. If you "need" that "MyNiceClass" is able to get something, you start by doing testGetSomething() in the test and set a basic expectation, then you write the public function getSomething() in the class and you end up having a one-to-one test for each method in 80% of the cases. The rest of the cases normally are multiple tests for the same method like for example testGetSomething() (happy path) and testGetSomethingThrowsExceptionWithInvalidParameter() (sad path).
In short
Yes, what you propose is correct, normal, usual and it is the recommended way to go according to the documentation.
Another reason (which was the reason in my case) is not using the complete class-name including the namespace.
// Should be like
#covers \App\Module\MyClass::doSomething
Why not simply run the test case and see the coverage with your changes? You risk getting down-voted as you are asking a question without trying anything.
From the PHPUnit manual:
The #covers annotation (see Table B.1) can be used in the test code to specify
which method(s) a test method wants to test. If provided, only the code
coverage information for the specified method(s) will be considered. Example
11.2 shows an example.
Table B1 Referenced above

Code coverage when not testing protected/private methods with PHPUnit

I know it's possible to test private/protected methods with PHPUnit using reflection or other workarounds.
But most sources tell me that it's not best practice to write tests for private methods inside of a class.
You are supposed to test the class as if it were a "black box" — you just test for expected behavior by comparing inputs with outputs disregarding the internal mechanics. Writing tests for classes should also notify you to unused private methods, by showing lack of code coverage.
When I test my class and generate an HTML report, it shows the private methods as not covered by tests, even though the lines from which they are called are absolutely executed/covered. I know that the private methods are executed, because if they weren't the assertions on my class would not pass.
Is this expected behavior in PHPUnit? Can I strive for 100% coverage, while still testing private methods only indirectly?
Some simplified example code (using RestBundle in Symfony2):
class ApiController extends FOSRestController {
/*
* #REST\View()
* #REST\Get("/api/{codes}")
*/
public function getCodesAction($codes) {
$view = new View();
$view->setHeader('Access-Control-Allow-Origin', '*');
$view->setData(array('type' => 'codes','data' => $this->_stringToArray($codes)));
$view->setFormat('json')->setHeader('Content-Type', 'application/json');
return $this->handleView($view);
}
private function _stringToArray($string){
return explode('+',$string);
}
The public function shows as "covered", the private function is indirectly covered but shows colored red in PHPUnit reports.
Test:
class ApiControllerTest extends WebTestCase {
public function test_getCodesAction(){
$client = static::createClient();
$client->request('GET', '/api/1+2+3');
$this->assertContains('{"type": "codes", "data": [1,2,3]}', $client->getResponse()->getContent());
}
}
This is just a silly example of course, I could just as well include the explode() right there in the public function; But the controllers I'm writing tests for contain much more intricate and re-usable private functions which transform data in more complex ways (but are still side-effect free).
In Phpunit you can specify the Covered Methods with special annotation, as descrived in the doc.
You can do something like this:
class ApiControllerTest extends WebTestCase {
/**
* #covers ApiController::getCodesAction
* #covers ApiController::_stringToArray
*/
public function test_getCodesAction(){
$client = static::createClient();
$client->request('GET', '/api/1+2+3');
$this->assertContains('{"type": "codes", "data": [1,2,3]}', $client->getResponse()->getContent());
}
}
Hope this help

How to prevent PhpStorm from showing an Expected... warning when using PHPUnit mocks?

When mocking an interface in PHPUnit, PhpStorm complains when it's used as parameter for a type-hinted function.
Example
interface InterfaceA{
}
class ClassA{
public function foo(InterfaceA $foo){}
}
class PhpStormTest extends PHPUnit_Framework_TestCase
{
public function testFoo(){
$mock = $this->getMock("InterfaceA");
$a = new ClassA();
$a->foo($mock);
}
}
On $a->foo($mock); PhpStorm underlines $mock with the warning Expected InterfaceA, got PHPUnit_Framework_MockObject_MockObject
Image
I guess it's happening because PHPUnit creates the mock a runtime and PhpStorm cannot know that it's actually implementing the interface.
I found a workaround to this problem in the Jetbrain blog at PhpStorm Type Inference and Mocking Frameworks. The important part:
By default, PhpStorm is capable of figuring out the available methods
on the mock object. However, it only displays those for PHPUnit’s
PHPUnit_Framework_MockObject_MockObject class. Fortunately, we can
solve this by instructing PhpStorm to infer type information from
other classes as well, by using a simple docblock comment.
So to make the warning disappear, we need to add /** #var InterfaceA */ /** #var InterfaceA|PHPUnit_Framework_MockObject_MockObject */ (cudos to Supericy) to let PhpStorm know our mock actually implements InterfaceA:
interface InterfaceA{
}
class ClassA{
public function foo(InterfaceA $foo){}
}
class PhpStormTest extends PHPUnit_Framework_TestCase
{
public function testFoo(){
/** #var InterfaceA|PHPUnit_Framework_MockObject_MockObject */
$mock = $this->getMock("InterfaceA");
$a = new ClassA();
$a->foo($mock);
}
}
This bugged me for some time, hope it helps someone :)
Edit
Since PHPUnit_Framework_MockObject_MockObject is really ugly to type, you can abbreviate it via MOOMOO and let PHPStorms auto-complete do the rest:
Another plugin I have used for this is the Dynamic Return Type Plugin, it lets you configure return types of methods in a very dynamic way (the example is to have better type information from Mocks).
Another, less verbose but possibly riskier, approach can be to wrap the call to getMock() with your own function and mark that with #return mixed:
/**
*
* #return mixed
*/
public function myGetMock($str)
{
return $this->getMock($str);
}
Calling this method instead of $this->getMock() will make the warning disappear.

PHPUnit Placeholder for empty tests

I like to have empty functions on occasion for placeholders (primarily empty constructors, since it helps avoid accidental duplication of constructors since my team knows there must always be one somewhere).
I also like to have at least one test for every method of a class (largely because it is a nice easy rule to hold my team against).
My question is simple: what should we put in these empty test methods to prevent the "no tests" warning.
We could just do $this->assertTrue(true), which I know will work just fine. However, I was wondering if there was anything a touch more official and proper (preferably something which makes it so the method isn't counted in the number of tests run, artificially inflating it a bit).
Thanks.
try this :
/**
* #covers Controllers\AdminController::authenticate
* #todo Implement testAuthenticate().
*/
public function testAuthenticate()
{
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
You try a reflection class on the function and ensure that the method is there. Then the test could simply be that the method exists (empty or not), which will pass without a warning.
class MethodExistsTest extends \PHPUnit_Framework_TestCase
{
protected $FOO;
protected function setUp()
{
$this->FOO = new \FOO();
}
/**
* #covers \FOO::Bar
*/
public function testEmptyMethodBarExists()
{
$ReflectionObject = new \ReflectionObject($this->FOO);
$this->assertTrue($ReflectionObject->getMethod('Bar'));
}
/**
* #covers \FOO::__construct
*/
public function testConstructorExists()
{
$ReflectionObject = new \ReflectionObject($this->FOO);
$this->assertNotNull($ReflectionObject->getConstructor());
}
}

Categories