PHP头条
热点:

PHP单元测试利器:PHPUnit深入理解(1)


在本系列文章的前两篇中初探PHP单元测试利器:PHPUnit和PHP单元测试利器:PHPUnit深入用法中,分别介绍了PHPUnit的基本用法和PHPUnit中的一些重要用法。在本文中,笔者将为大家介绍PHPUnit中的两个高级概念和用法,尽管它不一定在你的日常单元测试中都用到,但理解和学会它们的用法对学习PHPUnit还是十分重要的。

PHPUnit中的Annotations

如果有其他编程语言经验的开发者,应该对Annotations(注解)不陌生,其实在PHPUnit中,一个简单的如下面的一段注释也可以认为是Annotations:

  1. <?php  
  2. class MyTestClass extends PHPUnit_Framework_TestCase  
  3. {  
  4. /**  
  5. * Testing the answer to “do you love unit tests?”  
  6. */ 
  7. public function testDoYouLoveUnitTests()  
  8. {  
  9. $love = true;  
  10. $this->assertTrue($love);  
  11. }  
  12. }  
  13. ?> 

可以看到,其实一段以/** **/为标记的文字,就可以认为是一种Annotations,但Annotations其实不单单是简单的注释,它是与一个程序元素相关联信息或者元数据的标注,它不影响程序的运行,但相关的软件工具或框架能够将其转换成特殊的元数据标记,以方便开发者以更少的代码去提高效率(比如通过。如果你熟悉Java,则会发现在Java SE 5中及象Spring等框架中,都大量使用了Annotations。

然而,由于PHP并不象Java那样是编译性语言,因此本身缺乏去解析Annotations的机制,但幸好PHPUnit去提供了这样的功能,我们以下面的代码为例:

  1. <?php  
  2. class MyMathClass  
  3. {  
  4. /**  
  5. * Add two given values together and return sum  
  6. */ 
  7. public function addValues($a,$b)  
  8. {  
  9. return $a+$b;  
  10. }  
  11. }  
  12. ?> 

上面的只是一个简单的加法的例子,为此,我们使用Annotations去编写一个单元测试,在上两篇文章中,我们采用的是手工编写单元测试的方法,而本文中,将介绍使用PHPUnit命令行的方法,自动生成单元测试的框架,方法如下:

首先把上面的类保存为MyMathClass.PHP,然后在命令行下运行如下命令:

  1. phpunit –skeleton-test MyMathClass 

这时PHPUnit会自动生成如下的框架单元测试代码:

  1. <?php  
  2. require_once '/path/to/MyMathClass.php';  
  3. /**  
  4. * Test class for MyMathClass.  
  5. * Generated by PHPUnit on 2011-02-07 at 12:22:07.  
  6. */ 
  7. class MyMathClassTest extends PHPUnit_Framework_TestCase  
  8. {  
  9. /**  
  10. * @var MyMathClass  
  11. */ 
  12. protected $object;  
  13. /**  
  14. * Sets up the fixture, for example, opens a network connection.  
  15. * This method is called before a test is executed.  
  16. */ 
  17. protected function setUp()  
  18. {  
  19. $this->object = new MyMathClass;  
  20. }  
  21. /**  
  22. * Tears down the fixture, for example, closes a network connection.  
  23. * This method is called after a test is executed.  
  24. */ 
  25. protected function tearDown()  
  26. {  
  27. }  
  28. /**  
  29. * @todo Implement testAddValues().  
  30. */ 
  31. public function testAddValues()  
  32. {  
  33. // Remove the following lines when you implement this test.  
  34. $this->markTestIncomplete(  
  35. 'This test has not been implemented yet.' 
  36. );  
  37. }  
  38. }  
  39. ?> 

可以看到,PHPUnit为我们生成的单元测试代码自动引入了原来的MyMathClass.PHP,同时也生成了setUp和tearDown方法,但唯一的核心单元测试代码是留给了我们编写。如果想在这个基础上更快速的生成我们想要的单元测试代码,要如何实现呢?没错,就是使用annotations!我们可以在原来的MyMathClass.PHP中加入如下的annotations。

  1. <?php  
  2. class MyMathClass  
  3. {  
  4. /**  
  5. * Add two given values together and return sum  
  6. * @assert (1,2) == 3  
  7. */ 
  8. public function addValues($a,$b)  
  9. {  
  10. return $a+$b;  
  11. }  
  12. }  
  13. ?>  

然后再象上述一样在命令行运行:

  1. phpunit –skeleton-test MyMathClass 

这个时候会为我们生成如下的单元测试代码:

  1. <?php  
  2. /**  
  3. * Generated from @assert (1,2) == 3.  
  4. */ 
  5. public function testAddValues()  
  6. {  
  7. $this->assertEquals(  
  8. 3,  
  9. $this->object->addValues(1,2)  
  10. );  
  11. }  
  12. ?> 

看到了么?我们在原有的类中加入了注解@assert(1,2)==3,则PHPUnit自动为我们生成了正确的单元测试代码。当然,可以参考PHPUnit手册,学习到更多的关于@assert注解使用的规则。

下面再举一个例子来讲解annotations。假设我们的程序中的一个方法,只是仅需要数据的输入,并且不依赖XML或者数据库提供数据源,则为了测试这个方法,我们可能想到的一个方法是在程序中设置一个测试数据集去测试,但这里介绍一个比较简单的方法,就是使用注解@dataProvider,修改MyMathClass.PHP如下:

  1. <?php  
  2. /**  
  3. * Data provider for test methods below  
  4. */ 
  5. public static function provider()  
  6. {  
  7. return array(  
  8. array(1,2,3),  
  9. array(4,2,6),  
  10. array(1,5,7)  
  11. );  
  12. }  
  13. /**  
  14. * Testing addValues returns sum of two values  
  15. * @dataProvider provider  
  16. */ 
  17. public function testAddValues($a,$b,$sum)  
  18. {  
  19. $this->assertEquals(  
  20. $sum,  
  21. $this->object->addValues($a,$b)  
  22. );  
  23. }  
  24. ?> 

可以看到,这里使用了注解@dataProvider,指明了测试用例的数据提供者是由provider方法返回的一个数组。所以在单元测试时,数组中的第0个元素则会赋值给$a,第1个元素则会赋值给b,第3个元素则会赋值给sum,可以看到,上面的第3个数组提供的数据是不能通过单元测试的,因为1+5不等于7。

此外,这里还简单介绍两个常用的annotations,比如@expectedException注解可以测试代码中是否正确抛出了异常,比如:

  1. <?phprequire_once 'PHPUnit/Framework.php';   
  2. class ExceptionTest extends PHPUnit_Framework_TestCase{      
  3. /**    
  4.    * @expectedException InvalidArgumentException     */      
  5. public function testException()    {    
  6.   }  
  7. }  
  8.  
  9. ?>  

这里就用注解的方法表示testException中必须抛出的异常类型为InvalidArgumentException。

另外一个是@cover注解。它的作用是标识PHPUnit只为类中的哪些方法或作用域生成测试代码,比如:

  1. /**  
  2.      * @covers SampleClass::publicMethod  
  3.      * @covers SampleClass::<!public>  
  4.      * @covers HelperClass<extended>  
  5.      */ 
  6.     public function testMethod()  
  7.     {  
  8.         $result = SampleClass::method();  

则PHPUnit只为SampleClass类中的publicMethod方法、SampleClass类中的所有非public声明的方法和HelperClass类或者它的其中一个父类产生单元测试代码。


www.phpzy.comtrue/php/10078.htmlTechArticlePHP单元测试利器:PHPUnit深入理解(1) 在本系列文章的前两篇中初探PHP单元测试利器:PHPUnit和PHP单元测试利器:PHPUnit深入用法中,分别介绍了PHPUnit的基本用法和PHPUnit中的一些重要用法。...

相关文章

相关频道:

PHP之友评论

今天推荐