2012-08-03 72 views
7

我從API獲取JSON結構,並且需要檢查成功響應是否具有具有特定值的兩個特定屬性。如何測試對象的多個屬性

關鍵問題:

  1. 我不能比較整個對象,因爲有一些特性,其可以與每個請求
  2. 我不能寫兩次試驗(對於每個屬性)變化,因爲它可以只有當兩個屬性都匹配正確的值時才被視爲成功響應。

例成功的響應:

{ 
    'success': true, 
    'user_ip': '212.20.30.40', 
    'id': '7629428643' 
} 

骯髒的解決辦法是

<?php 
public function testAddAccount() { 
    $response = $this->api->addAccount('7629428643'); 

    $this->assertTrue(
     $response->success === TRUE && 
     $response->id === '7629428643' 
    ); 
} 

但我認爲必須有更好的和更清潔的解決方案,是嗎?

+2

這對我來說看起來很乾淨。 – Matt 2012-08-03 13:49:04

+0

該解決方案只能告訴你測試失敗,但不能告訴你究竟出了什麼問題,這就是爲什麼我認爲這是「髒」的原因。 – 2012-08-03 13:54:07

回答

0

如果assertTrue()存儲成功響應的布爾值,那麼我將如何處理它。請記住,這是味道的問題。

private $lastResponse; 
// $id given elsewhere 
public function testAddAccount($id) { 
    $this->lastResponse = $this->addAccount($id); 
} 

private function addAccount($id) { 
    return $this->api->addAccount($id); 
} 

private function isLastResponseValid($response){ 
    return $this->lastResponse->success === TRUE 
    && $this->lastResponse->id === '7629428643'; 
} 
0

對於這種情況,您可以在單個測試方法中使用多個斷言。此外,儘可能使用更具體的斷言,如assertEquals,因爲這些斷言將提供更好的失敗消息。

public function testAddAccount() { 
    $response = $this->api->addAccount('7629428643'); 

    self::assertTrue($response->success); 
    self::assertEquals('7629428643', $response->id); 
} 
0

正如在某些答案中提到的,您應該使用assertEquals()方法。第二部分是你可能會使用一些斷言。所以如果phpunit檢測到第一個斷言失敗,那麼整個測試都會失敗。

爲什麼不使用assertTrue()?因爲不清楚你是否在一個地方使用if ($object) ...,在另一個地方使用assertTrue($object);

此外,請確保您的例程正確執行。所以如果你在獲得響應時遇到異常 - 測試將失敗。而異常也應作爲測試用例進行檢查。也就是說,您應該嘗試發佈不正確的請求並引發異常。這是怎麼考好樣子 - 它應該檢查所有可能的情況,呵呵=)

所以,這是你應該得到的代碼:

public function testAddAccount() { 
    $response = $this->api->addAccount('7629428643'); 

    $this->assertEquals($response->success, true); 
    $this->assertEquals($response->id, '7629428643'); 

    $this->setExpectedException('MyException'); 

    $response = $this->api->addAccount('wrong_account'); 
} 
2

你想用assertEquals()爲要驗證每個屬性。儘管您通常只想在每個測試用例中測試一件事情,但爲了測試「一件事」,有時需要多個斷言。出於這個原因,多重斷言是可以的。

您可能還想聲明$response對象上存在屬性以避免發出通知。例子請參閱以下內容:

public function testAddAccount() { 
    // Attempt to create an account. 
    $response = $this->api->addAccount('7629428643'); 

    // Verify that the expected properties are present in the response. 
    $this->assertObjectHasAttribute('success', $response); 
    $this->assertObjectHasAttribute('id', $response); 

    // Verify the values of the properties. 
    $this->assertEquals(true, $response->success); 
    $this->assertEquals('7629428643', $response->id); 
} 
+0

儘管如此,它在方式上有點缺陷,即在失敗的情況下,它只會告訴你第一個有問題的斷言失敗,一旦你修復它,它會向你顯示另一個斷言。 – 2012-08-22 05:57:41

+0

這是事實,但無論如何,最好集中在一次失敗。修復第一次故障並不少見也會解決測試案例中的剩餘故障。 – JamesArmes 2012-08-22 20:15:06

0

我能想到的(雖然這口味的問題)將添加兩個布爾表達式,並斷言結果最徹底的方法就是二:

$r1=$response->success === TRUE; 
$r2=$response->id === '7629428643'; 
$this->assertEquals(2, $r1+$r2, "Expecting both values to match; got ($r1) and ($r2)"); 

當然,您可以將此設置擴展到任何數量的測試,包括數組和array_sum()==count()以及更多可愛的消息。

1

計算響應和正確答案之間的差異,忽略任何過多的值。如果沒有區別,一切都很好;如果有的話,你會得到完整的信息。

//some examples 
$responseValues = array('success' => true, 'user_ip' => '212.20.30.40', 'id' => '7629428643'); //success 
$errorResponseValues = array('success' => false, 'user_ip' => '212.20.30.40', 'id' => '7629428643'); //failure 
$errorResponseValues2 = array('success' => false, 'user_ip' => '212.20.30.40', 'id' => '123'); //failure 

$expectedValues = array('success' => true, 'id' => '7629428643'); //what is success 

function whatIsWrong($reality, $expectation) 
{ 
    return array_uintersect_assoc($reality, $expectation, function($a, $b){return (int)($a == $b);}); //This is slightly dirty, I think the final implementation is up to you 
} 

var_dump(whatIsWrong($responseValues, $expectedValues)); //array() 
var_dump(whatIsWrong($errorResponseValues, $expectedValues)); //array('success' => false) 
var_dump(whatIsWrong($errorResponseValues2, $expectedValues)); //array('success' => false, id => 123) 

然後你可以使用assertEqual便(whatIsWrong(...),陣列()),這應該輸出在失敗的差別,或者處理它在幾乎所有的首選方式。

相關問題