2009-10-20 117 views
17

當使用PHPUnit測試異常時,要求每個語句或斷言必須拋出異常以便測試通過的最佳方法是什麼?如何使用PHPUnit測試多個異常?

我基本上想要做的是這樣的:我來了;下面,做這項工作,但相當難看IMO

public function testExceptions() 
{ 

    $this->setExpectedException('Exception'); 

    foo(-1); //throws exception 
    foo(1); //does not throw exception 

} 

//Test will fail because foo(1) did not throw an exception 

public function testExceptions() 
{ 

    try { 
     foo(-1); 
    } catch (Exception $e) { 
     $hit = true; 
    } 

    if (!isset($hit)) 
     $this->fail('No exception thrown'); 

    unset($hit); 

    try { 
     foo(1); 
    } catch (Exception $e) { 
     $hit = true; 
    } 

    if (!isset($hit)) 
     $this->fail('No exception thrown'); 

    unset($hit); 

} 

回答

16

由於異常是程序流程中的大事件,因此在單個測試中測試多個異常是有問題的。

最簡單的事情就是簡單地將它分成兩個測試 - 第一個需要一個異常能夠通過,第二個只需要運行,並會失敗,它會拋出一個。根據它的命名,如果你願意的話,你可以在第二個測試中添加一些其他測試(可能會確認一個返回值),但我傾向於確保它仍然只做了一件重要的事情。

/** 
* @expectedException Exception 
*/ 
public function testBadFooThrowsException() 
{ 
    // optional, can also do it from the '@expectedException x' 
    //$this->setExpectedException('Exception'); 
    foo(-1); //throws exception -- good. 
} 

public function testFooDoesNotThrowException() 
{ 
    foo(1); //does not throw exception 
} 
+1

我確實看到你的觀點,儘管當每個測試的要點確保引發異常時,仍然感覺有多個測試有點奇怪。 – etheros 2009-10-21 14:13:57

+3

您還可以使用'@dataProvider註釋'來傳入值(甚至是預期的異常的名稱 - 用'$ this-> setExpectedException($ x)')。添加一個新的測試值(這將引發一個異常)只會是dataProvider函數中的另一個數組項。 – 2011-03-18 11:06:48

+1

羅伯特馬丁會說總是將病例分成不同的測試。在我看來,@ AlisterBulman答案顯示了該問題的完美解決方案。 – 2013-01-08 17:35:21

1

這對我沒有意義。

我想你試圖用一個測試用例來測試多個單獨的東西,這是不好的做法。

foo()引發預期的異常時,測試用例成功並且bar()將不會運行。

只是創建兩個單獨的測試用例,這是很少的代碼,那麼你在第二個列表中產生的。

或者解釋爲什麼在foo()失敗併發生異常之後運行bar()有意義時,它也會拋出異常。

+0

我試圖用不同的參數調用相同的函數(並且我編輯了我的示例以更好地反映這一點)。 PHPUnit手冊中的示例顯示了在單個測試中創建了多個相關的斷言,所以我試圖複製這個,但有例外。 – etheros 2009-10-20 12:49:22

6

稍微乾淨的代碼(但我還是建議分割你的測試:

try { 
    foo(-1); 
    $this->fail('No exception thrown'); 
} catch (Exception $e) {} 
0

擴大對@ dave1010的答案,這裏是我是如何解決這個問題,這可以讓你把所有這些「。斷言「在一個測試中是整潔和整潔的,你只需定義一個應該通過測試失敗的變量數組,然後遍歷每個變量,看看是否引發了異常;如果失敗(沒有異常拋出),則測試失敗,否則測試通過。

<?php 

public function testSetInvalidVariableType() 
{ 
    $invalid_vars = array(
     '',     // Strings 
     array(),   // Arrays 
     true,    // Booleans 
     1,     // Integers 
     new \StdClass  // Objects 
    ); 

    foreach ($invalid_vars as $var) { 
     try { 
      $object->method($var); 
      $this->fail('No exception thrown for variable type "' . gettype($var) . '".'); 
     } catch (\Exception $expected) { 
     } 
    } 
} 
+0

'失敗'拋出'PHPUnit_Framework_AssertionFailedError'。您需要在代碼中使用自定義例外。 – sectus 2016-10-05 05:13:50

15

我認爲這是單元測試中很常見的情況。我在這種情況下使用的方法是使用phpunit dataProviders。所有工作都如預期的那樣,並且測試代碼變得更加清晰和簡潔。

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function badValues() 
    { 
     return array(
      array(-1), 
      array(1) 
     ); 
    } 


    /** 
    * @dataProvider badValues 
    * @expectedException Exception 
    */ 
    public function testFoo($badValue) 
    { 
     foo($badValue); 
    } 
} 
+2

非常好的想法...用一個測試測試許多例外。 – Andrew 2015-06-25 20:12:17

+0

'array(1)'應該在那裏嗎? – 2016-01-27 03:10:06

+3

該解決方案是最美麗和優雅,必須是被接受的答案。 – 2016-04-29 06:17:21

相關問題