在本文中,筆者將為大家介紹phpunit中的兩個高級概念和用法,盡管它不一定在你的日常單元測試中都用到,但理解和學會它們的用法對學習phpunit還是十分重要的。
Phpunit中的Annotations
如果有其他編程語言經驗的開發者,應該對Annotations(注解)不陌生,其實在phpunit中,一個簡單的如下面的一段注釋也可以認為是Annotations:

<?php

class MyTestClass extends PHPUnit_Framework_TestCase

{

/**

* Testing the answer to “do you love unit tests?”

*/

public function testDoYouLoveUnitTests()

{

$love = true;

$this->assertTrue($love);

}

}

?>
可以看到,其實一段以/** **/為標記的文字,就可以認為是一種Annotations,但Annotations其實不單單是簡單的注釋,它是與一個程序元素相關聯信息或者元數據的標注,它不影響程序的運行,但相關的軟件工具或框架能夠將其轉換成特殊的元數據標記,以方便開發者以更少的代碼去提高效率(比如通過。如果你熟悉Java,則會發現在Java SE 5中及象Spring等框架中,都大量使用了Annotations。
然而,由於php並不象Java那樣是編譯性語言,因此本身缺乏去解析Annotations的機制,但幸好phpunit去提供了這樣的功能,我們以下面的代碼為例:

<?php

class MyMathClass

{

/**

* Add two given values together and return sum

*/

public function addValues($a,$b)

{

return $a+$b;

}

}

?>
上面的只是一個簡單的加法的例子,為此,我們使用Annotations去編寫一個單元測試,在上兩篇文章中,我們采用的是手工編寫單元測試的方法,而本文中,將介紹使用phpunit命令行的方法,自動生成單元測試的框架,方法如下:
首先把上面的類保存為MyMathClass.php,然後在命令行下運行如下命令:

phpunit –skeleton-test MyMathClass
這時phpunit會自動生成如下的框架單元測試代碼:

<?php

require_once '/path/to/MyMathClass.php';

/**

* Test class for MyMathClass.

* Generated by PHPUnit on 2011-02-07 at 12:22:07.

*/

class MyMathClassTest extends PHPUnit_Framework_TestCase

{

/**

* @var MyMathClass

*/

protected $object;

/**

* Sets up the fixture, for example, opens a network connection.

* This method is called before a test is executed.

*/

protected function setUp()

{

$this->object = new MyMathClass;

}

/**

* Tears down the fixture, for example, closes a network connection.

* This method is called after a test is executed.

*/

protected function tearDown()

{

}

/**

* @todo Implement testAddValues().

*/

public function testAddValues()

{

// Remove the following lines when you implement this test.

$this->markTestIncomplete(

'This test has not been implemented yet.'

);

}

}

?>
可以看到,phpunit為我們生成的單元測試代碼自動引入了原來的MyMathClass.php,同時也生成了setUp和tearDown方法,但唯一的核心單元測試代碼是留給了我們編寫。如果想在這個基礎上更快速的生成我們想要的單元測試代碼,要如何實現呢?沒錯,就是使用annotations!我們可以在原來的MyMathClass.php中加入如下的annotations。

<?php

class MyMathClass

{

/**

* Add two given values together and return sum

* @assert (1,2) == 3

*/

public function addValues($a,$b)

{

return $a+$b;

}

}

?>
然後再象上述一樣在命令行運行:

phpunit –skeleton-test MyMathClass
這個時候會為我們生成如下的單元測試代碼:

<?php

/**

* Generated from @assert (1,2) == 3.

*/

public function testAddValues()

{

$this->assertEquals(

3,

$this->object->addValues(1,2)

);

}

?>
看到了麼?我們在原有的類中加入了注解@assert(1,2)==3,則phpunit自動為我們生成了正確的單元測試代碼。當然,可以參考phpunit手冊,學習到更多的關於@assert注解使用的規則。
下面再舉一個例子來講解annotations。假設我們的程序中的一個方法,只是僅需要數據的輸入,並且不依賴XML或者數據庫提供數據源,則為了測試這個方法,我們可能想到的一個方法是在程序中設置一個測試數據集去測試,但這裡介紹一個比較簡單的方法,就是使用注解@dataProvider,修改MyMathClass.php如下:

<?php

/**

* Data provider for test methods below

*/

public static function provider()

{

return array(

array(1,2,3),

array(4,2,6),

array(1,5,7)

);

}

/**

* Testing addValues returns sum of two values

* @dataProvider provider

*/

public function testAddValues($a,$b,$sum)

{

$this->assertEquals(

$sum,

$this->object->addValues($a,$b)

);

}

?>
可以看到,這裡使用了注解@dataProvider,指明了測試用例的數據提供者是由provider方法返回的一個數組。所以在單元測試時,數組中的第0個元素則會賦值給$a,第1個元素則會賦值給b,第3個元素則會賦值給sum,可以看到,上面的第3個數組提供的數據是不能通過單元測試的,因為1+5不等於7。
此外,這裡還簡單介紹兩個常用的annotations,比如@expectedException注解可以測試代碼中是否正確拋出了異常,比如:

<?phprequire_once 'PHPUnit/Framework.php';

class ExceptionTest extends PHPUnit_Framework_TestCase{

/**

* @expectedException InvalidArgumentException */

public function testException() {

}

}


?>
這裡就用注解的方法表示testException中必須拋出的異常類型為InvalidArgumentException。
另外一個是@cover注解。它的作用是標識phpunit只為類中的哪些方法或作用域生成測試代碼,比如:

/**

* @covers SampleClass::publicMethod

* @covers SampleClass::<!public>

* @covers HelperClass<extended>

*/

public function testMethod()

{

$result = SampleClass::method();

}
則phpunit只為SampleClass類中的publicMethod方法、SampleClass類中的所有非public聲明的方法和HelperClass類或者它的其中一個父類產生單元測試代碼。
當前1/2頁 12下一頁閱讀全文