2012-08-03 71 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(...),阵列()),这应该输出在失败的差别,或者处理它在几乎所有的首选方式。