13

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"
}
]
9
  • Can you paste the litteral $response? Commented Aug 7, 2014 at 19:22
  • is there any error that is occurring (undefined index, illegal offset, something along those lines)? Commented Aug 7, 2014 at 19:24
  • 1
    Maybe you need to use $response->getContent()? Commented Aug 7, 2014 at 19:26
  • @Don'tPanic - Thanks for responding! I tried $response->getContent() in the json_decode() with the exact same result. Commented Aug 7, 2014 at 19:28
  • 1
    Wait, shouldn't your controller return $posts instead of echoing it? Commented Aug 7, 2014 at 19:35

4 Answers 4

12

Hope you figured it out by now but here is what I use:

$array = json_decode($response->getContent());

Sign up to request clarification or add additional context in comments.

2 Comments

I specifically used $this->response->getContent().
And for the status: $response->getStatusCode()
4

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.

Comments

3

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'

Comments

2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.