2017-04-04 1 views
1

J'utilise PhpUnit avec de bons résultats, en testant mon code avec des assertions seulement. Récemment, j'ai décidé d'essayer PhpUnit avec l'analyse du rapport de couverture, mais j'ai remarqué que les tests qui utilisent les méthodes dataProvider ont tendance à diminuer mes scores de couverture de code. Je me demande ce que je peux faire mal ou si c'est une conséquence des techniques de test dataProvider? J'utilise PhpUnit 6 avec Php 7.Pourquoi les fournisseurs de données PhpUnit réduisent-ils les scores de couverture?

J'ai inclus une classe source, Foo, avec trois classes de test en dessous qui la testent. FooTest utilise des méthodes de test régulières, pas de dataProviders. BarTest utilise les méthodes dataProvider avec les annotations @codeCoverageIgnore et BazTest utilise les méthodes dataProvider sans annotations.

Vous pouvez voir comment le score de couverture de code est inférieur avec BazTest.

Terminal screenshot of phpunit invocation.

Code Coverage report screenshot with all test classes.

Code Coverage report screenshot with BazTest detail.

fichier foo.php

namespace phpunittestproject\src; 


/** 
* Foo 
* 
* This is a simple class to be used as a source file 
* in unit test experiments. It gets and sets a name 
* string and date object. 
* 
*/ 
class Foo 
{ 



    /** 
    * Name 
    * 
    * String characters other than numeric. 
    * 
    * @var string 
    */ 
    private $name = null; 

    /** 
    * Date 
    * 
    * Date no older than 2000. 
    * 
    * @var \DateTime 
    */ 
    private $date = null; 


    /** 
    * Constructor 
    * 
    * Sets instance vars. 
    * 
    */ 
    public function __construct() 
    { 

     $this->name = ''; 
     $this->date = new \DateTime('now'); 

    } 


    /** 
    * Get Date 
    * 
    * @return DateTime 
    */ 
    public function getDate() 
    { 
     return $this->date; 
    } 

    /** 
    * Get Name 
    * 
    * @return string 
    */ 
    public function getName() 
    { 
     return $this->name; 
    } 

    /** 
    * Set Date 
    * 
    * This method accepts a DateTime object that corresponds 
    * to a date no earlier than 2000. 
    * 
    * @param \DateTime $value Date after 2000. 
    * @return boolean Result of operation. 
    */ 
    public function setDate(\DateTime $value) 
    { 
     if($value < new \DateTime('2000-01-01 00:00:00')){ 
      return false; 
     } else { 
      $this->date = $value; 
      return true; 
     } 
    } 

    /** 
    * Set Name 
    * 
    * This method accepts a string that does not contain numeric 
    * characters. 
    * 
    * @param string $value String without numeric characters. 
    * @return boolean Result of operation. 
    */ 
    public function setName(string $value) 
    { 
     if(preg_match('/\\d/', $value)){ 
      return false; 
     } else { 
      $this->name = $value; 
      return true; 
     } 
    } 

} 

FooTest.php:

declare(strict_types = 1); 

namespace phpunittestproject\test; 

use \phpunittestproject\src\Foo; 

/** 
* 
* Foo Test 
* 
* This test class does not use dataProvider methods. All 
* test assertions are being done in test metods. 
* 
*/ 
class FooTest extends \PHPUnit\Framework\TestCase 
{ 


    /** 
    * 
    * 
    */ 
    public function testGetDate() 
    { 
     $foo = new Foo(); 

     // Good date: 
     $date = new \DateTime('2011-01-01 11:11:11'); 
     $foo->setDate($date); 
     $this->assertEquals($date, $foo->getDate()); 

     // Bad date: 
     $date = new \DateTime('1990-01-01 11:11:11'); 
     $foo->setDate($date); 
     $this->assertNotEquals($date, $foo->getDate()); 

    } 

    /** 
    * 
    * 
    */ 
    public function testGetName() 
    { 
     $foo = new Foo(); 

     // Good name: 
     $foo->setName('A Good Name'); 
     $this->assertEquals('A Good Name', $foo->getName()); 

     // Bad name: 
     $foo->setName('Bad Name 666'); 
     $this->assertNotEquals('Bad Name 666', $foo->getName()); 

    } 

    /** 
    * Test setDate() 
    * 
    * This test method tests the date property when it is 
    * set with good and bad data using method setDate(). 
    * 
    */ 
    public function testSetDate() 
    { 
     $foo = new Foo(); 

     // Good date: 
     $date = new \DateTime('2011-01-01 11:11:11'); 
     $foo->setDate($date); 
     $this->assertAttributeEquals($date, 'date', $foo); 

     // Bad date: 
     $date = new \DateTime('1990-01-01 11:11:11'); 
     $foo->setDate($date); 
     $this->assertAttributeNotEquals($date, 'date', $foo); 

    } 

    /** 
    * 
    * Test setName() 
    * 
    * This test method tests the name property when it is 
    * set with good and bad data using method setName(). 
    * 
    * 
    */ 
    public function testSetName() 
    { 
     $foo = new Foo(); 

     // Good name: 
     $foo->setName('Good Name'); 
     $this->assertAttributeEquals('Good Name', 'name', $foo); 

     // Bad name: 
     $foo->setName('Bad Name 666'); 
     $this->assertAttributeNotEquals('', 'name', $foo); 

    } 

} 

BarTest.php:

declare(strict_types = 1); 

namespace phpunittestproject\test; 

use \phpunittestproject\src\Foo; 

/** 
* 
* Bar Test 
* 
* This test class utilizes dataProvider methods to feed 
* test methods. The dataProvider methods are annotated 
* with codeCoverageIgnore. 
* 
*/ 
class BarTest extends \PHPUnit\Framework\TestCase 
{ 


    /** 
    * 
    * @codeCoverageIgnore 
    */ 
    public function providerTestSetDateWithInvalidData() 
    { 
     return array(
       array(new \DateTime('1990-01-01 11:11:11')), 
     ); 
    } 

    /** 
    * 
    * @codeCoverageIgnore 
    */ 
    public function providerTestSetDateWithValidData() 
    { 
     return array(
       array(new \DateTime('2011-01-01 11:11:11')), 
     ); 
    } 

    /** 
    * 
    * @codeCoverageIgnore 
    */ 
    public function providerTestSetNameWithInvalidData() 
    { 
     return array(
       array('Bad Name 666'),    
     ); 
    } 

    /** 
    * 
    * @codeCoverageIgnore 
    */ 
    public function providerTestSetNameWithValidData() 
    { 
     return array(
       array('Good Name'), 
     ); 
    } 

    /** 
    * 
    * 
    */ 
    public function testGetDate() 
    { 
     $foo = new Foo(); 
     $date = new \DateTime('2001-01-01 11:11:11'); 
     $foo->setDate($date); 
     $this->assertEquals($date, $foo->getDate()); 
    } 

    /** 
    * 
    * 
    */ 
    public function testGetName() 
    { 
     $foo = new Foo(); 
     $foo->setName('A Good Name'); 
     $this->assertEquals('A Good Name', $foo->getName()); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetDateWithInvalidData 
    * 
    * 
    */ 
    public function testSetDateWithInvalidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setDate($value); 
     $this->assertAttributeNotEquals($value, 'date', $foo); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetDateWithValidData 
    * 
    * 
    */ 
    public function testSetDateWithValidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setDate($value); 
     $this->assertAttributeEquals($value, 'date', $foo); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetNameWithInvalidData 
    * 
    * 
    */ 
    public function testSetNameWithInvalidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setName($value); 
     $this->assertAttributeNotEquals($value, 'name', $foo); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetNameWithValidData 
    * 
    * 
    */ 
    public function testSetNameWithValidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setName($value); 
     $this->assertAttributeEquals($value, 'name', $foo); 
    } 

} 

BazTest.php:

declare(strict_types = 1); 

namespace phpunittestproject\test; 

use \phpunittestproject\src\Foo; 


/** 
* 
* Baz Test 
* 
* This test class utilizes dataProvider methods to feed 
* test methods. The dataProvider methods are not annotated 
* with codeCoverageIgnore. 
* 
*/ 
class BazTest extends \PHPUnit\Framework\TestCase 
{ 


    /** 
    * 
    * 
    */ 
    public function providerTestSetDateWithInvalidData() 
    { 
     return array(
       array(new \DateTime('1990-01-01 11:11:11')), 
     ); 
    } 

    /** 
    * 
    * 
    */ 
    public function providerTestSetDateWithValidData() 
    { 
     return array(
       array(new \DateTime('2011-01-01 11:11:11')), 
     ); 
    } 

    /** 
    * 
    * 
    */ 
    public function providerTestSetNameWithInvalidData() 
    { 
     return array(
       array('Bad Name 666'),    
     ); 
    } 

    /** 
    * 
    * 
    */ 
    public function providerTestSetNameWithValidData() 
    { 
     return array(
       array('Good Name'), 
     ); 
    } 

    /** 
    * 
    * 
    */ 
    public function testGetDate() 
    { 
     $foo = new Foo(); 
     $date = new \DateTime('2001-01-01 11:11:11'); 
     $foo->setDate($date); 
     $this->assertEquals($date, $foo->getDate()); 
    } 

    /** 
    * 
    * 
    */ 
    public function testGetName() 
    { 
     $foo = new Foo(); 
     $foo->setName('A Good Name'); 
     $this->assertEquals('A Good Name', $foo->getName()); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetDateWithInvalidData 
    * 
    * 
    */ 
    public function testSetDateWithInvalidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setDate($value); 
     $this->assertAttributeNotEquals($value, 'date', $foo); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetDateWithValidData 
    * 
    * 
    */ 
    public function testSetDateWithValidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setDate($value); 
     $this->assertAttributeEquals($value, 'date', $foo); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetNameWithInvalidData 
    * 
    * 
    */ 
    public function testSetNameWithInvalidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setName($value); 
     $this->assertAttributeNotEquals($value, 'name', $foo); 
    } 

    /** 
    * 
    * @dataProvider providerTestSetNameWithValidData 
    * 
    * 
    */ 
    public function testSetNameWithValidData($value) 
    { 
     $foo = new Foo(); 
     $foo->setName($value); 
     $this->assertAttributeEquals($value, 'name', $foo); 
    } 

} 

phpunit.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<phpunit colors="true" bootstrap="./vendor/autoload.php"> 
    <testsuites> 
     <testsuite name="DataProviderTestSuite"> 
      <file>phpunittestproject/test/FooTest.php</file> 
      <file>phpunittestproject/test/BarTest.php</file> 
      <file>phpunittestproject/test/BazTest.php</file> 
     </testsuite> 
    </testsuites> 
    <filter> 
     <whitelist> 
      <file>phpunittestproject/test/FooTest.php</file> 
      <file>phpunittestproject/test/BarTest.php</file> 
      <file>phpunittestproject/test/BazTest.php</file> 
     </whitelist> 
    </filter> 
</phpunit> 
+1

Je pense que vous devez supprimer les fichiers de test à partir de votre liste blanche. Vous ne faites pas de couverture de code sur vos tests eux-mêmes, c'est pour vous dire quelles parties de votre code d'application couvrent vos tests. – Christopher

+1

Cela a résolu Christopher merci! J'ai édité le fichier phpunit.xml afin que les éléments du fichier whitelist soient remplacés par un seul élément ' phpunittestproject/src/Foo.php'. Génial! – peej

Répondre

0

Merci @Christopher pour la solution! Un fichier phpunit.xml mal configuré a amené PhpUnit à tester les tests. La modification des éléments de la liste blanche a corrigé le score de couverture du code bas. Les méthodes dataProvider n'ont pas besoin d'être annotées avec @codeCoverageIgnore!

<?xml version="1.0" encoding="UTF-8"?> 
<phpunit colors="true" bootstrap="./vendor/autoload.php"> 
    <testsuites> 
     <testsuite name="DataProviderTestSuite"> 
      <!-- Test files go here: --> 
      <file>phpunittestproject/test/FooTest.php</file> 
      <file>phpunittestproject/test/BarTest.php</file> 
      <file>phpunittestproject/test/BazTest.php</file> 
     </testsuite> 
    </testsuites> 
    <filter> 
     <whitelist> 
      <!-- Source files to be tested go here: --> 
      <file>phpunittestproject/src/Foo.php</file> 
     </whitelist> 
    </filter> 
</phpunit> 

Code coverage HTML report with 100% score.