2017-04-04 6 views
1

私は良い結果を得てPhpUnitを使用しており、アサーションだけで自分のコードをテストしています。最近、私はカバレッジレポート分析でPhpUnitを試すことにしましたが、dataProviderメソッドを使用するテストでは、コードカバレッジスコアが低下する傾向にあることに気付きました。私は何が間違っているのだろうか、これがdataProviderのテスト技術の結果であるのだろうか?私はPHP 7でPhpUnit 6を使用しています。なぜPhpUnitデータプロバイダはカバレッジスコアを下げますか?

私はソースクラスFooをテストし、その下に3つのテストクラスを含めました。 FooTestは定期的なテストメソッドを使用しますが、dataProvidersは使用しません。 BarTestは@codeCoverageIgnoreアノテーションでdataProviderメソッドを使用し、BazTestはアノテーションなしでdataProviderメソッドを使用します。

BazTestを使用すると、コードカバレッジスコアがどのように低いかを確認できます。

Terminal screenshot of phpunit invocation.

Code Coverage report screenshot with all test classes.

Code Coverage report screenshot with BazTest detail.

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:解決のための@Christopher

<?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

私はあなたのホワイトリストからテストファイルを削除する必要があると思います。テストでコードカバレッジを実行することはありません。これは、テストでカバーするアプリケーションコードのどの部分を伝えるかを示します。 – Christopher

+1

それはそれを解決したクリストファーのおかげで!ホワイトリストファイルの要素が ' phpunittestproject/src/Foo.php'という単一の要素に置き換えられるように、phpunit.xmlファイルを編集しました。非常にすばらしい! – peej

答えて

0

ありがとう!誤って設定されたphpunit.xmlファイルにより、PhpUnitはテストをテストしていました。ホワイトリスト要素を編集することで、低いコードカバレッジスコアが修正されました。 dataProviderメソッドに@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.

関連する問題