如何测试对象的多个属性

时间:2012-08-03 13:46:45

标签: php phpunit

我从API获取JSON结构,需要检查成功响应是否具有两个具有特定值的特定属性。

关键问题:

  1. 我无法比较整个对象,因为有些属性可能因每个请求而异。
  2. 我无法编写两个测试(针对每个属性),因为只有当两个属性都匹配正确的值时才能将其视为成功响应。
  3. 示例成功回复:

    {
        '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'
        );
    }
    

    但我认为必须有更好更清洁的解决方案,是吗?

6 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分: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(...),array()),它应该在失败时输出差异,或以几乎任何偏好的方式处理它。

答案 2 :(得分: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';
}

答案 3 :(得分:0)

对于这样的情况,您可以在单个测试方法中使用多个断言。此外,尽可能使用更具体的断言,例如assertEquals,因为这些断言将提供更好的失败消息。

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

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

答案 4 :(得分: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');
}

答案 5 :(得分: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()的任意数量的测试,以及更可爱的消息。