2017-06-29 69 views
0

我最近開始使用PHPUnit進行單元測試,並且構造了我的測試以檢查函數成功和失敗時的正確行爲。PHPUnit - 在兩個相關函數失敗時將Mark測試失敗

例如,我可以測試函數connectToDevice(),期望在連接成功時返回true,否則返回false。然後,我將有:

public function testConnectToDeviceSuccess() 
{ 
    $this->assertTrue($this->myObject->connectToDevice()); 
} 

public function testConnectToDeviceFailure() 
{ 
    $this->assertFalse($this->myObject->connectToDevice()); 
} 

目前這些功能必然失敗的一個,然後PHPUnit的將報告我1次失敗。相反,我會將它設置爲僅在兩個函數失敗時纔將測試標記爲失敗。因此,當1成功時,另一個將被跳過。

這可能在PHPUnit中維護這些測試在兩個不同的功能?

+0

唯一一次失敗的時候是你有錯誤,否則其中一個總是爲真或假。如果你在測試中有錯誤,測試不會結束(只有當你沒有發現錯誤時)。 – Edwin

+0

@Edwin問題是我不想有幾十個應該失敗的失敗測試。此外,函數可能會拋出一個意外的異常,這將導致兩個函數都失敗,從而導致測試失敗。 – DrKey

+0

那麼你在做錯了什麼,無論是在測試中還是在開發中。測試應該始終有效,如果你想測試失敗,只需以你確定沒有連接存在的方式設置你的環境=> connectToDevice將是錯誤的。 – Edwin

回答

1

我認爲你遇到的問題是你缺少一個確保正確測試結果的設置。這聽起來可能有點奇怪,但考慮到這種情況下

class ConnectedResource 
{ 
    private $connector; 

    public function __construct($connector) 
    { 
     $this->connector = $connector; 
    } 

    public function connectToDevice() 
    { 
     try { 
      $this->connector->connect(); 
     } catch (\Exception $e) { 
      return false; 
     } 

     return true; 
    } 
} 

這真的是簡化,但基本的一點是,要測試兩個路徑:connect()的成功和例外。

你會做什麼在您的測試,現在要麼是

public function testSuccessfulConnectReturnsTrue() 
{ 
    $connector = new Connector(
     // config to make a successful connection 
    ); 
    $myObject = new ConnectedResource($connector); 

    $this->assertTrue($myObject->connectToDevice()); 
} 

public function testFailedConnectReturnsFalse() 
{ 
    $connector = new Connector(
     // invalid config that will raise an exception 
    ); 
    $myObject = new ConnectedResource($connector); 

    $this->assertFalse($myObject->connectToDevice()); 
} 

現在這兩個測試將工作,因爲他們使用不同的連接(一個工程,一個是沒有)。

另一種可能性是通過模擬連接器。換句話說,而不是一個真正的連接器,你創建一個虛擬對象,你可以自己決定什麼$this->connector->connect()會返回。把它看作是「假設我有一個連接器返回true,那麼ConnectedResource應該表現得如此」。該代碼,這可能是這個樣子:

public function testSuccessfulConnectReturnsTrue() 
{ 
    $connector = $this->createMock(Connector::class); 
    $connector->expect($this->any()) 
     ->method('connect') 
     ->willReturn(true) 
    ; 
    $myObject = new ConnectedResource($connector); 

    $this->assertTrue($myObject->connectToDevice()); 
} 

以及失敗的情況會是這個樣子:

public function testFailedConnectReturnsFalse() 
{ 
    $connector = $this->createMock(Connector::class); 
    $connector->expect($this->any()) 
     ->method('connect') 
     ->willReturn($this->throwException(new Exception)) 
    ; 
    $myObject = new ConnectedResource($connector); 

    $this->assertTrue($myObject->connectToDevice()); 
} 

現在你控制測試(連接)的範圍之外的一切並且只測試connectToDevice()中定義的行爲。這樣可以使您的測試免受其他課程中的變更的影響,但是例如在將來更新connect()函數發生變化時可能會導致問題。參數被添加或改變。

重要的是,您必須確保滿足您的測試運行要求。

1

這是可能的(你可以做一個測試依賴於其他測試的結果,看Test Dependencies),但是考慮你會在你的問題,有效地測試這裏的東西,包裹在一個測試:

public function testConnectToDeviceBehavior() 
{ 
    $actual = $this->myObject->connectToDevice() === $this->myObject->connectToDevice(); 
    $this->assertTrue($actual); 
} 

如果並且僅當連接到設備時沒有兩次給出相同的結果,這將使測試失敗。

您可以在多個測試中編寫測試依賴關係,但這最有可能不是您想要測試的結果。

但是,如果檢查Phpunit文檔的鏈接部分。

否則考慮the other answer中概述的內容,使用依賴注入並測試您的對象是否有工作和連接失敗的設備。