yayuj's avatar

Mysterious 100% test coverage

I'm studying unit testing and I started seeing some projects made by the creator of the PHPUnit and I saw this project: https://github.com/sebastianbergmann/money/ - The thing is that he has several classes and I saw every single test of him and he doesn't test them, but they are all 100% coverage, how is that possible? What is that magic?

0 likes
9 replies
JarekTkaczyk's avatar

@yayuj There's no magic in there. He got 4 classes, one of which is JsobSerializable with literally one method, that is covered in the MoneyTest. Other 3 classes have their tests MoneyTest, CurrencyTest and IntlFormatterTest.

There are also currencies that are simple implementations of Money, exceptions that are not tested of course and interfaces, again, not tested.

But speaking of - it is really good example of how to get 100% of real coverage, ie. by using @cover and @uses annotations.

First tells PHPUnit to include specified method in the coverage, latter tells the opposite - that the method is used in the flow but shouldn't be included in the coverage report.

1 like
yayuj's avatar

If you look at the coverage you will see that there are classes that extends Money who hasn't been tested, but how are they there on the coverage and with 100%? - I'm implementing the Simple Factory pattern and I'm using the factory to create a concrete class, it appears on the coverage, but the other classes that the factory can create doesn't appear.

JarekTkaczyk's avatar

@yayuj Have you seen the contents of these classes? Like I said, they are simple implementations of the Money class. They do nothing but just provide new Currency('XXX') to the constructor, which is tested in MoneyTest.

yayuj's avatar

@JarekTkaczyk - I'm confused, totally confused (I'm almost without my hair :D). - can you please, try to make this code with 100% coverage? Thank you in advance.

JarekTkaczyk's avatar

@yayuj let me give you just a sample, you will do the rest:

// Pizza.php is like in your paste

// Pizza test goes below
<?php

/**
 * @group pizza
 */
class PizzaTest extends \PHPUnit_Framework_TestCase {

    public function setUp()
    {
        $this->pizza = $this->getMockForAbstractClass('Pizza');
    }

    /**
     * @test
     * @covers Pizza::setName
     * @covers Pizza::getName
     */
    public function testSetGetName()
    {
        $name = 'Pepperoni';
        $this->pizza->setName($name);
        $this->assertEquals($name, $this->pizza->getName());
    }
    /**
     * @test
     * @covers Pizza::setDescription
     * @covers Pizza::getDescription
     */
    public function testSetGetDescription()
    {
        $description = 'Pepperoni flavoured pizza.';
        $this->pizza->setDescription($description);
        $this->assertEquals($description, $this->pizza->getDescription());
    }
}


// --------------------------------------
// run the test
➜  path git:(master) ✗ phpunit --group pizza --coverage-text
PHPUnit 4.4.1 by Sebastian Bergmann.

Configuration read from /path/phpunit.xml

..

Time: 607 ms, Memory: 10.50Mb

OK (2 tests, 2 assertions)


Code Coverage Report:   
  2015-02-04 17:13:50   

 Summary:               
  Classes: 100.00% (1/1)
  Methods: 100.00% (4/4)
  Lines:   100.00% (6/6)

Pizza
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% (  6/  6)

yayuj's avatar

But I'm doing this, the part where I'm confused is the factory. This part I understand that I can use @covers to cover a method, as you are doing, but what about the new dependency of ``PizzaFactorywhere I'm testing a concrete classGreek`? I mean, how can I mimic the behavior of the factory and don't use the concrete class?

Please or to participate in this conversation.