在PHPUnit中,斷言(Assertions)是其提供的一系列對程序執行結果測試的方法:
assertArrayHasKey(mixed $key, array $array[, string $message = ''])
斷言數組$array含有索引$key, $message用於自定義輸出的錯誤信息,后同
assertClassHasAttribute(string $attributeName, string $className[, string $message = ''])
斷言類$className含有屬性$attributeName
assertClassHasStaticAttribute(string $attributeName, string $className[, string $message = ''])
斷言類$className含有靜態屬性$attributeName
assertContains(mixed $needle, Iterator|array $haystack[, string $message = ''])
斷言迭代器對象$haystack/數組$haystack含有$needle
assertNotContains()
與上條相反
assertAttributeContains(mixed $needle, Class|Object $haystack[, string $message = ''])
斷言$needle為一個類/對象$haystack可訪問到的屬性(public, protected 和 private)
assertAttributeNotContains()
與上條相反
assertContains(string $needle, string $haystack[, string $message = ''])
斷言字符串$needle在字符串$haystack中
assertContainsOnly(string $type, Iterator|array $haystack[, boolean $isNativeType = NULL, string $message = ''])
斷言迭代器對象/數組$haystack中只有$type類型的值, $isNativeType 設定為PHP原生類型,$message同上
assertNotContainsOnly()
與上條相反
assertAttributeContainsOnly() 和 assertAttributeNotContainsOnly()
斷言對象的屬性只有$type類型和非含有$type類型
assertEmpty(mixed $actual[, string $message = ''])
斷言$actual為空
assertNotEmpty()
遇上條相反
assertAttributeEmpty() 和 assertAttributeNotEmpty()
斷言對象的所有屬性為空或不為空
assertEqualXMLStructure(DOMNode $expectedNode, DOMNode $actualNode[, boolean $checkAttributes = FALSE, string $message = ''])
斷言Dom節點$actualNode和DOM節點$expectedNode相同,$checkAttributes FALSE 不斷言節點屬性,TRUE則斷言屬性$message同上
assertEquals(mixed $expected, mixed $actual[, string $message = ''])
斷言復合類型$actual與$expected相同
assertNotEquals()
與上條相反
assertAttributeEquals() and assertAttributeNotEquals()
斷言類屬性$actual與$expected相同
assertEquals(array $expected, array $actual[, string $message = ''])
斷言數組$actual和數組$expected相同
assertFalse(bool $condition[, string $message = ''])
斷言$condition的結果為false
assertFileEquals(string $expected, string $actual[, string $message = ''])
斷言文件$actual和$expected相同
assertFileExists(string $filename[, string $message = ''])
斷言文件$filename存在
assertFileNotExists()
與上條相反
assertGreaterThan(mixed $expected, mixed $actual[, string $message = ''])
斷言$actual比$expected大
assertAttributeGreaterThan()
斷言類的屬性用
assertGreaterThanOrEqual(mixed $expected, mixed $actual[, string $message = ''])
斷言$actual大於等於$expected
assertAttributeGreaterThanOrEqual()
斷言類的屬性
assertInstanceOf($expected, $actual[, $message = ''])
斷言$actual為$expected的實例
assertNotInstanceOf()
與上相反
assertAttributeInstanceOf() and assertAttributeNotInstanceOf()
斷言類屬性用
assertInternalType($expected, $actual[, $message = ''])
斷言$actual的類型為$expected
assertNotInternalType()
與上相反
assertAttributeInternalType() and assertAttributeNotInternalType()
斷言類屬性用
assertLessThan(mixed $expected, mixed $actual[, string $message = ''])
斷言$actual小於$expected
assertAttributeLessThan()
斷言類屬性小於$expected
assertLessThanOrEqual(mixed $expected, mixed $actual[, string $message = ''])
斷言$actual小於等於$expected
assertAttributeLessThanOrEqual()
斷言類屬性小於等於$expected
assertNull(mixed $variable[, string $message = ''])
斷言$variable的值為null
assertNotNull()
與上條相反
assertObjectHasAttribute(string $attributeName, object $object[, string $message = ''])
斷言$object含有屬性$attributeName
assertObjectNotHasAttribute()
與上條相反
assertRegExp(string $pattern, string $string[, string $message = ''])
斷言字符串$string符合正則表達式$pattern
assertNotRegExp()
與上條相反
assertStringMatchesFormat(string $format, string $string[, string $message = ''])
斷言$string符合$format定義的格式,例如 %i %s等等
assertStringNotMatchesFormat()
與上條相反
assertStringMatchesFormatFile(string $formatFile, string $string[, string $message = ''])
斷言$string路徑的文件的格式和$formatFile文件的格式相同
assertStringNotMatchesFormatFile()
與上條相反
assertSame(mixed $expected, mixed $actual[, string $message = ''])
斷言$actual和$expected的類型和值相同
assertNotSame()
與上條相反
assertAttributeSame() and assertAttributeNotSame()
斷言類屬性用
assertSame(object $expected, object $actual[, string $message = ''])
斷言對象$actual和對象$expected相同
assertSelectCount(array $selector, integer $count, mixed $actual[, string $message = '', boolean $isHtml = TRUE])
斷言在$actual文檔中(格式為html或xml)css選擇器$selector有$count個,或有符合$selector的元素(設定$count為true),或沒有符合$selector的元素(設定$count為false)
assertSelectCount("#binder", true, $xml); // 有一個就行
assertSelectCount(".binder", 3, $xml); // 必須有3個?
assertSelectEquals(array $selector, string $content, integer $count, mixed $actual[, string $message = '', boolean $isHtml = TRUE])
斷言在文檔$actual中有符合根據$selector的找到符合$content的$count個元素,當$count等於true和false的時候作用如下:
assertSelectEquals("#binder .name", "Chuck", true, $xml); // 所有的name等於Chuck
assertSelectEquals("#binder .name", "Chuck", false, $xml); // 所有的name不等於Chuck
assertSelectRegExp(array $selector, string $pattern, integer $count, mixed $actual[, string $message = '', boolean $isHtml = TRUE])
assertStringEndsWith(string $suffix, string $string[, string $message = ''])
斷言$string的末尾為$suffix結束
assertStringEndsNotWith()
與上條相反
assertStringEqualsFile(string $expectedFile, string $actualString[, string $message = ''])
斷言$actualString在文件$expectedFile的內容中
assertStringNotEqualsFile()
與上條相反
assertStringStartsWith(string $prefix, string $string[, string $message = ''])
斷言$string的開頭為$suffix
assertStringStartsNotWith()
與上條相反
assertTag(array $matcher, string $actual[, string $message = '', boolean $isHtml = TRUE])
斷言$actual的內容符合$matcher的定義,matcher的定義如下:
1、 id: 節點必須帶有id屬性且名稱與id設定的相同
2、tags: 節點的名稱必須與tags的值匹配
3、attributes: 節點的屬性必須與$attributes數組中的值相匹配
4、content: 文本內容必須與$content的值相同.
5、parent: 節點的父節點必須符合$parent數組中定義的內容.
6、child: 節點的字節點中有至少一個直系子節點滿足 $child 數組中定義的內容.
7、ancestor: 節點的父節點中有至少一個節點滿足 $ancestor 數組中定義的內容.
8、descendant: 節點的字節點中有至少一個子節點滿足 $descendant 數組中定義的內容.
9、children: 用於計算字節點的聯合數組
10、count: 符合匹配標准的字節點數目需要和count的值相同
11、less_than: 符合匹配標准的字節點數目需要比count的值少
12、greater_than: 符合匹配標准的字節點數目需要比count的值多
13、 only: 另外一個聯合數組用於定義配合標准的節點,只有這些節點才會被計算入內
Another associative array consisting of the keys to use to match on the children, and only matching children will be counted
assertTag的代碼例子(圖片點擊放大):
More complex assertions can be formulated using the PHPUnit_Framework_Constraint classes
更加復雜的斷言可以通過PHPUnit_Framework_Constraint類來制定
測試方法間的依賴關系
PHPUnit可以實現測試方法的依賴關系,也就是說,一個測試方法的參數的內容和是否會運行依賴於另外一個測試方法結果,依賴關系通過注釋@depends來定義.這個特性一般用於檢查代碼的邏輯過程,一個邏輯的執行前提是另外一個邏輯的執行結果。
例子:
在上面的測試類StackTest中,定義了2個依賴測試方法,testPush依賴於testEmpty, testPop依賴於testPush。
那么在測試運行時,testEmpty中的斷言執行完畢也沒有出現問題時,方法中的return語句會將 $stack傳給依賴於它的testPush,作為testPush的參數傳入到testPush中,testPush執行完畢之后,也會將$stack傳給依賴於它的testPop,只要斷言檢查沒有出現異常,那么PHPUnit就會根據依賴關系依次執行依賴的測試方法,直到依賴關系結束為止。
另外,為了方便快速的確定問題的所在,如果某個測試方法依賴的方法測試沒有功過,那么PHPUnit會自動跳過后面所有的依賴測試。
例子:
testOne中斷言為True,但是傳入的是false,testOne的測試不會通過,那么依賴於testOne的testTwo也會被自動跳過.
數據提供者(Data Providers)
在前面的例子我們可以看到:測試方法是可以有參數的,在依賴關系中參數的值是它依賴的測試方法傳入.那么某個測試方法沒有依賴的方法,我們怎么給它傳入參數做測試呢?PHPUnit給我們提供了數據提供者方法來為測試方法傳入數據.
數據提供者方法需要定義在當前的測試類中,在測試方法的注釋中使用@dataProvider標簽標注給它提供數據的方法名,定義之后PHPUnit會自動的將數據提供者方法返回的數據依次傳入到測試方法中測試.
數據提供者相當於都取大量數據測試時的封裝
代碼:
在上面的代碼中,方法add_provider就是測試方法testAdd的數據提供者方法,它會依次給testAdd傳入4組測試數據,testAdd會測試4次.
注意:數據提供者方法返回數據的格式: 需要返回的是2維數組,第二維數組值的位置,對應測試方法參數的位置,參數個數和數組長度要相等,否則PHPUnit會報錯,下面是個用於理解的簡單的例子:
array(參數1,參數2,參數3,參數4,參數N),
array(參數1,參數2,參數3,參數4,參數N),
);
除了數組外,PHPUnit還支持數據提供者方法返回迭代器對象,迭代器的介紹估計大部分PHPer比較陌生,詳細的介紹可以去http://php.net/manual/en/class.iterator.php 查看。
來看代碼(點擊圖片放大察看):
和前一個例子實現的測試內容相同,但是數據提供者返回的是一個迭代器對象而不是是數組
數據提供者方法和依賴關系的限制
當一個測試方法依賴於另外一個使用data providers測試方法時,這個測試方法將會在它依賴的方法至少測試成功一次后運行,同時使用data providers的測試方法的執行的結果不能傳入一個依賴它的測試方法中.這個解釋來自官方的文檔,理解起來可能有點難,我們通過代碼來描述下這個限制:
上面代碼例子中:
情況1: add_provider提供的數據至少有一對數據相等
testC會執行一次, 因為testC是依賴於testB的, 但是testB使用了數據提供者方法,那么testC中是無法收到testB return的值的
情況2: add_provider提供的數據沒有一對數據相等
testC永遠不會執行
測試異常
有時需要測試某些情況下代碼是否按照要求拋出了相關的異常。
在PHPUnit中,有3種方式來檢查異常是否拋出。
方法一: 注釋法, 用@expectedException 標定期待的異常
* @expectedException InvalidArgumentException
*/
public function testException()
{
}
方法二: 設定法,使用 $this->setExpectedException 設定期待的異常
{
$this->setExpectedException('InvalidArgumentException');
}
方法三: try catch + fail法
try {
// 這里寫上會引發異常的代碼
} catch (InvalidArgumentException $expected) {
// 抓到異常測試通過
return ;
}
// 沒抓到異常就算失敗
$this->fail('An expected exception has not been raised.' );
}
測試PHP錯誤
有時,代碼在運行時會出現php錯誤,如整除0,文件不存在等等.在PHPUnit中,它會自動把錯誤轉換為異常PHPUnit_Framework_Error並拋出,我們只需要在測試方法中設定抓取這個異常即可:
* @expectedException PHPUnit_Framework_Error // 期待PHPUnit_Framework_Error的異常
*/
public function testFailingInclude()
{
// include一個不存在的文件,就會拋出一個PHPUnit_Framework_Error的異常
include 'not_existing_file.php';
}