Reputation: 16827
Trying to learn too many new things at once here (Laravel, PHPUnit, etc), so this is probably just a tired brain problem, would still appreciate some help.
I have a very basic 'Blog' project using Laravel as the API layer and AngularJS as the front end. I want to unit test the API end-points but I am having trouble figuring out how to process JSON while in my test functions.
When I try to run testGetBlogPosts() I see what looks like the JSON output in my CLI, but I am unable to json_decode() and check that certain parts of the object match my expected result. Here I simply want to make sure that the ID on the first object in the result array is ID "1".
The result I receive from the test is: 1) ExampleTest::testGetBlogPosts ErrorException: Trying to get property of non-object
Any help or suggestions is much appreciated!
TL;DR: Test case is not correctly processing JSON response from API endpoint
Controller
class HomeController extends BaseController {
/*
|--------------------------------------------------------------------------
| Default Home Controller
|--------------------------------------------------------------------------
|
| You may wish to use controllers instead of, or in addition to, Closure
| based routes. That's great! Here is an example controller method to
| get you started. To route to this controller, just add the route:
|
| Route::get('/', 'HomeController@showWelcome');
|
*/
public function showWelcome()
{
return View::make('hello');
}
public function getBlogPosts()
{
$posts = Post::get()->take(5)->toJson();
// echo $posts; PER THE ACCEPTED ANSWER, RETURN NOT ECHO
return $posts;
}
public function getSinglePost($postId)
{
$posts = Post::find($postId)->toJson();
// echo $posts; PER THE ACCEPTED ANSWER, RETURN NOT ECHO
return $posts;
}
}
Test File
class ExampleTest extends TestCase {
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
$crawler = $this->client->request('GET', '/');
$this->assertTrue($this->client->getResponse()->isOk());
}
public function testGetBlogPosts()
{
$response = $this->call('GET', 'api/getBlogPosts');
$array = json_decode($response);
$result = false;
if($array[0]->id == 1)
{
$result = true;
}
$this->assertEquals(true, $result);
}
}
As requested, the full test output
root@homestead:/home/vagrant/Laravel/Homestead/Blog# phpunit PHPUnit 3.7.28 by Sebastian Bergmann.
Configuration read from /home/vagrant/Laravel/Homestead/Blog/phpunit.xml
.E[{"id":"1","user_id":"1","title":"This is a test post","post_body":"testststs","created_at":"2014-08-07 19:26:26","updated_at":"2014-08-07 19:26:26"},{"id":"2","user_id":"75","title":"Libero rerum rem praesentium et et at doloribus asperiores.","post_body":"Commodi aut beatae aut veritatis eum soluta sint. In aut cumque iure quis.","created_at":"2014-08-07 19:26:26","updated_at":"2014-08-07 19:26:26"}]
Time: 1.85 seconds, Memory: 18.50Mb
There was 1 error:
1) ExampleTest::testGetBlogPosts ErrorException: Trying to get property of non-object
/home/vagrant/Laravel/Homestead/Blog/app/tests/ExampleTest.php:22
FAILURES! Tests: 2, Assertions: 1, Errors: 1.
If I go to this endpoint in a browser I get this
[
{
id: 1,
user_id: 1,
title: "This is a test post",
subtitle: "",
post_body: "testststs",
created_at: "2014-08-07 19:26:04",
updated_at: "2014-08-07 19:26:04"
},
{
id: 2,
user_id: 18,
title: "Rem deserunt dolor odit tempore qui eaque labore.",
subtitle: "",
post_body: "Ea a adipisci molestiae vel dignissimos. Ea blanditiis et est.",
created_at: "2014-08-07 19:26:04",
updated_at: "2014-08-07 19:26:04"
}
]
Upvotes: 13
Views: 21177
Reputation: 40841
You can call the json
method directly off the response object.
$response = $this->getJson('/foo');
$json = $response->json(); // ['foo' => 'bar', 'baz' => 'boo']
It also accepts a key as an argument.
$foo = $response->json('foo'); // 'bar'
Upvotes: 3
Reputation: 3108
Adding a method in /tests/TestCase.php
helps a lot:
/**
* dumps json result
* @param string $function can be print_r, var_dump or var_export
* @param boolean $json_decode
*/
public function dump($function = 'var_export', $json_decode = true) {
$content = $this->response->getContent();
if ($json_decode) {
$content = json_decode($content, true);
}
// ❤ ✓ ☀ ★ ☆ ☂ ♞ ☯ ☭ € ☎ ∞ ❄ ♫ ₽ ☼
$seperator = '❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤ ❤';
echo PHP_EOL . $seperator . PHP_EOL;
$function($content);
echo $seperator . PHP_EOL;
return $this;
}
Then you can call it at any point after json call:
public function testInvalidPostID() {
$this->json('PUT', '/posts/2222/sh-comments/1001', [
'input' => 'SomeThing'
], [
'Authorization' => 'Bearer ' . app('jwt')->getTokenForUser(2)
])->dump() //dumpnig output as array
->seeJsonStructure(['errors' => [
'*' => [
'message'
]
]
])->assertResponseStatus(404);
}
Upvotes: 2
Reputation: 41810
The getBlogPosts()
method in your controller echos $post
rather than returning it. This means that the $response
in your test will not have anything in it to json_decode
.
Upvotes: 4
Reputation: 606
Hope you figured it out by now but here is what I use:
$array = json_decode($response->getContent());
Upvotes: 12