Laravel 尝试对 API JSON 响应进行单元测试

Posted

技术标签:

【中文标题】Laravel 尝试对 API JSON 响应进行单元测试【英文标题】:Laravel Trying To Unit Test API JSON Response 【发布时间】:2014-10-01 03:55:08 【问题描述】:

在这里尝试一次学习太多新东西(Laravel、phpUnit 等),所以这可能只是一个疲惫的大脑问题,仍然希望得到一些帮助。

我有一个非常基本的“博客”项目,使用 Laravel 作为 API 层,AngularJS 作为前端。我想对 API 端点进行单元测试,但在我的测试函数中无法弄清楚如何处理 JSON。

当我尝试运行 testGetBlogPosts() 时,我在 CLI 中看到了类似于 JSON 输出的内容,但我无法执行 json_decode() 并检查对象的某些部分是否符合我的预期结果。这里我只是想确保结果数组中第一个对象的 ID 是 ID“1”。

我从测试中收到的结果是: 1) ExampleTest::testGetBlogPosts ErrorException: 试图获取非对象的属性

非常感谢任何帮助或建议!

TL;DR:测试用例未正确处理来自 API 端点的 JSON 响应

控制器

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;
    


测试文件

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

根据要求,完整的测试输出

root@homestead:/home/vagrant/Laravel/Homestead/Blog# phpunit PHPUnit 塞巴斯蒂安·伯格曼 3.7.28。

配置读取自 /home/vagrant/Laravel/Homestead/Blog/phpunit.xml

.E["id":"1","user_id":"1","title":"这是一个测试 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 et at doloribus asperiores。","post_body":"Commodi aut beatae aut veritatis eum soluta sint。在自私自利 quis.","created_at":"2014-08-07 19:26:26","updated_at":"2014-08-07 19:26:26"]

时间:1.85 秒,内存:18.50Mb

有 1 个错误:

1) ExampleTest::testGetBlogPosts ErrorException: Trying to get 非对象的属性

/home/vagrant/Laravel/Homestead/Blog/app/tests/ExampleTest.php:22

失败!测试:2,断言:1,错误:1。

如果我在浏览器中访问这个端点,我会得到这个

[

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"

]

【问题讨论】:

你能粘贴一下$response吗? 是否发生了任何错误(未定义的索引、非法偏移、类似的情况)? 也许你需要使用$response->getContent() @Don'tPanic - 感谢您的回复!我在 json_decode() 中尝试了 $response->getContent(),结果完全相同。 等等,你的控制器不应该返回 $posts 而不是回显它吗? 【参考方案1】:

希望你现在明白了,但这是我使用的:

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

【讨论】:

我专门用$this->response->getContent() 对于状态:$response->getStatusCode()【参考方案2】:

控制器中的 getBlogPosts() 方法会回显 $post 而不是返回它。这意味着您的测试中的$response 将没有任何内容到json_decode

【讨论】:

【参考方案3】:

您可以直接从响应对象中调用json 方法。

$response = $this->getJson('/foo');
$json = $response->json(); // ['foo' => 'bar', 'baz' => 'boo']

它也接受一个键作为参数。

$foo = $response->json('foo'); // 'bar'

【讨论】:

【参考方案4】:

/tests/TestCase.php 中添加一个方法很有帮助:

/**
 * 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;

那么你可以在json调用之后的任何时候调用它:

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

【讨论】:

以上是关于Laravel 尝试对 API JSON 响应进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

使用 Laravel 从 API 获取 JSON 响应

Laravel 404 和 500 的 API 和网站中的不同响应(JSON 和网页)?

使用自定义 json 响应进行 Laravel 验证

对惯性响应和 json 响应使用相同的方法 Laravel Jetstream

Laravel api 响应时间很慢?

使用Laravel测试JSON响应