成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

PHP單元測試利器:PHPUnit深入理解

開發 后端
在本文中,筆者將為大家介紹PHPUnit中的兩個高級概念和用法,盡管它不一定在你的日常單元測試中都用到,但理解和學會它們的用法對學習PHPUnit還是十分重要的。

在本系列文章的前兩篇中初探PHP單元測試利器:PHPUnitPHP單元測試利器: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類或者它的其中一個父類產生單元測試代碼。

#p#

PHPUnit中的Mocking

在介紹Mocking前,先來看下為什么要使用Mocking。舉一個數據庫查詢的例子,比如在某個應用中,如果要測試一個數據庫的應用,但假如這個數據庫的測試要耗費很多資源以及編寫很復雜的單元測試的代碼的話,可以嘗試使用Mocking技術。舉例說明如下:

  1. <?php  
  2. class Database  
  3. {  
  4. public function reallyLongTime()  
  5. {  
  6. $results = array(  
  7. array(1,'test','foo value')  
  8. );  
  9. sleep(100);  
  10. return $results;  
  11. }  
  12. }  
  13. ?> 

在上面這個例子中,我們模擬了一個數據庫的操作,認為它需要運行很長時間。接下來我們編寫其單元測試代碼如下:

  1. <?php  
  2. require_once '/path/to/Database.php';  
  3. class DatabaseTest extends PHPUnit_Framework_TestCase  
  4. {  
  5. private $db = null;  
  6. public function setUp()  
  7. {  
  8. $this->db = new Database();  
  9. }  
  10. public function tearDown()  
  11. {  
  12. unset($this->db);  
  13. }  
  14. /**  
  15. * Test that the "really long query" always returns values  
  16. */ 
  17. public function testReallyLongReturn()  
  18. {  
  19. $mock = $this->getMock('Database');  
  20. $result = array(  
  21. array(1,'foo','bar test')  
  22. );  
  23. $mock->expects($this->any())  
  24. ->method('reallyLongTime')  
  25. ->will($this->returnValue($result));  
  26. $return = $mock->reallyLongTime();  
  27. $this->assertGreaterThan(0,count($return));  
  28. }  
  29. }  
  30. ?>  

注意看這段代碼中有趣的地方,這里,使用了PHPUnit中的getMock對象方法,這里實際上是模擬生成一個Database類的“偽實例”了,這里生成了$mock這個mock對象實例,以方便接著的單元測試中用到。接下來的這三行代碼:

  1.  $mock->expects($this->any())  
  2. ->method('reallyLongTime')  
  3. ->will($this->returnValue($result)); 

它們的含義為:無論方法reallyLongtime執行了多長時間,始終最后會直接返回$result這個數組的結果。這樣,你就可以通過mocking技術很輕易地去實現在單元測試中,繞過某些復雜的邏輯部分,而節省大量的寶貴時間提高測試效率。

下面的這個例子,講解的是Mocking技術中的更高級用法Mockbuilder。依然以上面的例子說明:

  1. <?php  
  2. public function testReallyLongRunBuilder()  
  3. {  
  4. $stub = $this->getMockBuilder('Database')  
  5. ->setMethods(array(  
  6. 'reallyLongTime' 
  7. ))  
  8. ->disableAutoload()  
  9. ->disableOriginalConstructor()  
  10. ->getMock();  
  11. $result = array(array(1,'foo','bar test'));  
  12. $stub->expects($this->any())  
  13. ->method('reallyLongTime')  
  14. ->will($this->returnValue($result));  
  15. $this->assertGreaterThan(0,count($return));  
  16. }  
  17. ?> 

通過使用Mockbuilder,我們可以不用通過構造函數的方法去初始化一個mock對象。這段代碼跟上一段代碼的功能其實是一樣的,只不過留意一下新的兩個方法: disableAutoload和disableOriginalConstructor,其功能分別是禁止使用PHP的內置的autoload初始構造方法和禁止調用該類原有的構造函數。最后再看一個例子:

  1. <?php  
  2. /**  
  3. * Testing enforcing the type to "array" like the "enforceTypes"  
  4. * method does via type hinting  
  5. */ 
  6. public function ttestReallyLongRunBuilderConstraint()  
  7. {  
  8. $stub = $this->getMock('Database',array('reallyLongTime'));  
  9. $stub->expects($this->any())  
  10. ->method('reallyLongTime')  
  11. ->with($this->isType('array'));  
  12. $arr = array('test');  
  13. $this->assertTrue($stub-> reallyLongTime ($arr));  
  14. }  
  15. ?> 

在這里,我們使用了with方法,其中這個方法中指定了要傳入的參數類型為array數組類型,最后這個斷言是通過了,因為返回的的確是數組類型。
 

【編輯推薦】

  1. PHP單元測試利器:PHPUnit深入用法
  2. 初探PHP單元測試利器:PHPUnit
  3. PHP開發者工資翻倍需做到的5件事
  4. PHP企業級應用之常見緩存技術深入解讀
  5. PHP 5.3.6 RC1發布 修復多處BUG(附下載)
責任編輯:陳貽新 來源: it168
相關推薦

2011-02-16 09:45:13

PHPPHPUnit

2011-02-15 10:05:48

PHPPHPUnit

2024-08-15 08:11:10

2011-08-22 13:57:55

gtest

2017-01-14 23:42:49

單元測試框架軟件測試

2011-11-18 15:18:41

Junit單元測試Java

2017-04-07 13:45:02

PHP單元測試數據庫測試

2009-11-18 12:38:04

PHP字符串函數

2010-06-28 10:12:01

PHP匿名函數

2009-11-16 17:20:04

PHP多維數組排序

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap數據結構hash函數

2020-07-21 08:26:08

SpringSecurity過濾器

2024-04-26 11:14:34

C#單元測試框架

2015-12-02 10:52:11

PHPUnitWindows配置

2017-01-16 12:12:29

單元測試JUnit

2017-01-14 23:26:17

單元測試JUnit測試

2020-08-18 08:10:02

單元測試Java

2017-03-23 16:02:10

Mock技術單元測試

2021-05-05 11:38:40

TestNGPowerMock單元測試
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩成人一区二区 | 永久看片 | 亚洲欧美日韩在线 | 一级黄色录像毛片 | 黄色男女网站 | 亚洲精品久久久蜜桃 | 成人三区 | 伊人久操 | 草樱av| 在线播放国产一区二区三区 | 亚洲精品1区2区3区 91免费看片 | 免费观看国产视频在线 | 国产精品亚洲综合 | 国产精品久久久久久久一区探花 | 午夜视频精品 | 午夜在线视频 | 国产一区二 | 亚洲精品视频一区 | 国产精品揄拍一区二区 | 色播久久久 | 51ⅴ精品国产91久久久久久 | 性色视频在线观看 | 国产三级国产精品 | 欧美精品三区 | 精品久久久久国产 | 美女国产 | 亚洲欧美另类在线观看 | 日韩在线小视频 | 日韩精品影院 | 精品国产乱码久久久久久蜜退臀 | 中文字幕一区在线 | 激情欧美一区二区三区中文字幕 | 久久久久久91 | 亚洲一区不卡在线 | 毛片免费在线 | 久久国产精品免费一区二区三区 | 无码日韩精品一区二区免费 | 国产91在线播放精品91 | 国产91在线视频 | 国产精品我不卡 | 97视频精品 |