For the first time I'm trying to use unit tests for my projects, but I'm blocked with a test asserting that a model is properly stored.
This is the API controller I want to test:
public function store(QuestionFormRequest $request)
{
$questionRequest = $request->question();
$question = new Question($questionRequest);
$question->save();
$question->answers()->createMany($questionRequest['answers']);
return response()->json($question->load('answers'), 201);
}
This is my test:
public function it_can_store_a_question()
{
$surveyFactory = factory(Survey::class)->create();
$themeFactory = factory(Theme::class)->create();
$pillarFactory = factory(Pillar::class)->create();
$questionToStore = [
'survey_id' => $surveyFactory->id,
'theme_id' => $themeFactory->id,
'pillar_id' => $pillarFactory->id,
'name' => 'question',
'type' => 'simple',
'answers' => [
[
'label' => 'reponse1',
'points' => '3',
],
[
'label' => 'reponse2',
'points' => '5',
]
]
];
$response = $this->post('/api/1.0/question', $questionToStore);
$response->assertStatus(201);
$expectedQuestion = Question::with('answers')->get()->first();
$this->assertEquals(json_encode($expectedQuestion), $response->getContent());
}
This is the result:
Failed asserting that two strings are equal.
Expected :'{"id":1,"survey_id":1,"theme_id":1,"pillar_id":1,"name":"question","type":"simple","created_at":"2017-08-29 08:54:45","updated_at":"2017-08-29 08:54:45","deleted_at":null,"answers":[{"id":1,"question_id":1,"label":"reponse1","points":3,"description":"","created_at":"2017-08-29 08:54:45","updated_at":"2017-08-29 08:54:45","deleted_at":null},{"id":2,"question_id":1,"label":"reponse2","points":5,"description":"","created_at":"2017-08-29 08:54:45","updated_at":"2017-08-29 08:54:45","deleted_at":null}]}'
Actual :'{"survey_id":1,"theme_id":1,"pillar_id":1,"name":"question","type":"simple","updated_at":"2017-08-29 08:54:45","created_at":"2017-08-29 08:54:45","id":1,"answers":[{"id":1,"question_id":1,"label":"reponse1","points":3,"description":"","created_at":"2017-08-29 08:54:45","updated_at":"2017-08-29 08:54:45","deleted_at":null},{"id":2,"question_id":1,"label":"reponse2","points":5,"description":"","created_at":"2017-08-29 08:54:45","updated_at":"2017-08-29 08:54:45","deleted_at":null}]}'
In fact, the result is right. But not in the same order. What am I doing wrong in my test?
Thanks.
For your example you could use assertions shipped with phpunit/phpunit:
assertJsonFileEqualsJsonFile()assertJsonStringEqualsJsonString()assertJsonStringEqualsJsonFile()or
assertEquals()assertJsonFileEqualsJsonFile()However, when I - for the sake of an example - extract the two JSON strings into separate files
expected.jsonactual.jsonand then format the JSON in PhpStorm with option + command + L and run the following test
use PHPUnit\Framework;
final class JsonTest extends Framework\TestCase
{
public function testJsonEquals()
{
$expected = __DIR__ . '/expected.json';
$actual = __DIR__ . '/actual.json';
$this->assertJsonFileEqualsJsonFile($expected, $actual);
}
}
the test fails with
Failed asserting that '{\n
"id": 1,\n
"survey_id": 1,\n
"theme_id": 1,\n
"pillar_id": 1,\n
"name": "question",\n
"type": "simple",\n
"created_at": "2017-08-29 08:54:45",\n
"updated_at": "2017-08-29 08:54:45",\n
"deleted_at": null,\n
"answers": [\n
{\n
"id": 1,\n
"question_id": 1,\n
"label": "reponse1",\n
"points": 3,\n
"description": "",\n
"created_at": "2017-08-29 08:54:45",\n
"updated_at": "2017-08-29 08:54:45",\n
"deleted_at": null\n
},\n
{\n
"id": 2,\n
"question_id": 1,\n
"label": "reponse2",\n
"points": 5,\n
"description": "",\n
"created_at": "2017-08-29 08:54:45",\n
"updated_at": "2017-08-29 08:54:45",\n
"deleted_at": null\n
}\n
]\n
}\n
' matches JSON string "{
"survey_id": 1,
"theme_id": 1,
"pillar_id": 1,
"name": "question",
"type": "simple",
"updated_at": "2017-08-29 08:54:45",
"created_at": "2017-08-29 08:54:45",
"id": 1,
"answers": [
{
"id": 1,
"question_id": 1,
"label": "reponse1",
"points": 3,
"description": "",
"created_at": "2017-08-29 08:54:45",
"updated_at": "2017-08-29 08:54:45",
"deleted_at": null
},
{
"id": 2,
"question_id": 1,
"label": "reponse2",
"points": 5,
"description": "",
"created_at": "2017-08-29 08:54:45",
"updated_at": "2017-08-29 08:54:45",
"deleted_at": null
}
]
}
".
--- Expected
+++ Actual
@@ @@
{
- "id": 1,
"survey_id": 1,
"theme_id": 1,
"pillar_id": 1,
"name": "question",
"type": "simple",
+ "updated_at": "2017-08-29 08:54:45",
"created_at": "2017-08-29 08:54:45",
- "updated_at": "2017-08-29 08:54:45",
- "deleted_at": null,
+ "id": 1,
What you can see is that in fact the two JSON strings aren't equal, at least the order of the fields isn't the same. The problem with the output of the assertion is that it's not really helpful, simply because the assertion just compares the two strings.
assertEquals()Nonetheless, when we json_decode() the content of the files and then assert using assertEquals() like this:
use PHPUnit\Framework;
final class JsonTest extends Framework\TestCase
{
public function testJsonEquals()
{
$expected = json_decode(file_get_contents(__DIR__ . '/expected.json'), true);
$actual = json_decode(file_get_contents(__DIR__ . '/actual.json'), true);
$this->assertEquals($expected, $actual);
}
}
then the test fails again, but with output that is actually much more helpful:
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
- 'deleted_at' => null
As you can see, there's an actual difference between the data - the root object node is missing a deleted_at field with a value of null.
Note So, the question boils down to
Depending on which is important to you, pick whichever assertion makes more sense to you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With