Reputation: 16146
I'm getting a JSON structure from an API and need to check, whether the successfull response has two specific attributes with specific values.
Key problems:
Example successful response:
{
'success': true,
'user_ip': '212.20.30.40',
'id': '7629428643'
}
Dirty solution would be
<?php
public function testAddAccount() {
$response = $this->api->addAccount( '7629428643' );
$this->assertTrue(
$response->success === TRUE &&
$response->id === '7629428643'
);
}
But I think there must be better and cleaner solution, is there?
Upvotes: 8
Views: 2729
Reputation: 1452
Compute the difference between the response and the right answer ignoring any excessive values. If there's no difference, everything's fine; if there is, you'll get the complete information.
//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)
Then you may use assertEqual(whatIsWrong(...), array()), which should output the difference on failure, or handle it in pretty much any preferred way.
Upvotes: 1
Reputation: 5460
The cleanest way I can think of (although this is a matter of taste) would be to add the two boolean expressions and assert the result is two:
$r1=$response->success === TRUE;
$r2=$response->id === '7629428643';
$this->assertEquals(2, $r1+$r2, "Expecting both values to match; got ($r1) and ($r2)");
Of course, you can extend this setup to any number of tests with arrays and array_sum()==count()
, and more loveable messages.
Upvotes: 0
Reputation: 1373
You want to use assertEquals()
for each property you want to verify. While you typically want to test only one thing in each test case, sometimes multiple assertions are required in order to test that "one thing". For this reason, multiple assertions are okay.
You may also want to assert that the properties exist on the $response
object to avoid notices. See the following for an example:
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);
}
Upvotes: 2
Reputation: 12265
As mentioned in some answer, you should use assertEquals()
method. The second part is that you might use a few assertions. So if the phpunit detects failure on the first assertion, the whole test fails.
Why not to use assertTrue()
? Because it is not clear if you, for example, use if ($object) ...
in one place of code and assertTrue($object);
in other one.
Also, be sure your routine executes correctly. So if you get the exception while trying to get the response - test will fail. While exceptions should be checked also as a test cases. That is, you should try posting an incorrect request and assert exception is thrown. That's how good test looks like - it should check all possible situations, hehe =)
So, this is the code you should got:
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');
}
Upvotes: 0
Reputation: 36562
You can use multiple assertions in a single test method for cases like this. Also, use the more specific assertions such as assertEquals
whenever possible as these will provide better failure messages.
public function testAddAccount() {
$response = $this->api->addAccount( '7629428643' );
self::assertTrue($response->success);
self::assertEquals('7629428643', $response->id);
}
Upvotes: 0
Reputation: 4669
If assertTrue()
stores the boolean of a succesfull response this is the way how I would handle it. Keep in mind that this is a matter of taste.
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';
}
Upvotes: 0