简体   繁体   English

我可以使用Laravel的`call`方法在单元测试中发送原始JSON数据吗?

[英]Can I use Laravel's `call` method to send raw JSON data in a unit test?

I am attempting to unit test my implementation of a Stripe webhook handler. 我试图对我的Stripe webhook处理程序的实现进行单元测试。 Stripe webhook data comes across the wire as raw JSON in the body of a POST request, so I capture and decode the data as such: 条带webhook数据作为POST请求正文中的原始JSON在线上传播,因此我捕获并解码数据:

public function store()
{
    $input = @file_get_contents("php://input");
    $request = json_decode($input);
    return Json::encode($request);
}

I'm attempting to unit test this code, but I can't figure out how to send raw JSON data in a unit test such that I can retrieve it with the file_get_contents("php:input//") function. 我正在尝试对此代码进行单元测试,但我无法弄清楚如何在单元测试中发送原始JSON数据,以便我可以使用file_get_contents("php:input//")函数检索它。 This is what I've tried (using PHPUnit ): 这是我尝试过的(使用PHPUnit ):

protected $testRoute = 'api/stripe/webhook';

protected $validWebhookJson = <<<EOT
{
  "id": "ch_14qE2r49NugaZ1RWEgerzmUI",
  "object": "charge",
  // and a bunch of other fields too
}
EOT;

public function testWebhookDecdoesJsonIntoObject()
{
    $response = $this->call('POST', $this->testRoute, $this->validWebhookJson); // fails because `$parameters` must be an array
    $response = $this->call('POST', $this->testRoute, [], [], ['CONTENT_TYPE' => 'application/json'], $this->validWebhookJson);
    dd($response->getData(true)); // array(0) {} BOOOO!!! Where for to my data go?
}

I've also tried curl but that would make an external request, which doesn't make sense to me from a unit-testing perspective. 我也尝试过curl但这会产生一个外部请求,从单元测试的角度来看,这对我没有意义。 How can I simulate a POST request with raw JSON data in the body that will be picked up by my store method? 如何使用我的store方法拾取的正文中的原始JSON数据来模拟POST请求?

You can. 您可以。 But you need to send the encoded JSON as the content (aka request body) and not the parameter. 但是您需要将编码的JSON作为内容(也称为请求主体)而不是参数发送。

$this->call(
    'POST',
    '/articles',
    [],
    [],
    [],
    $headers = [
        'HTTP_CONTENT_LENGTH' => mb_strlen($payload, '8bit'),      
        'CONTENT_TYPE' => 'application/json',
        'HTTP_ACCEPT' => 'application/json'
    ],
    $json = json_encode(['foo' => 'bar'])
);

That's the 7th parameter. 那是第7个参数。

If you look at the method definition (in Laravel's core) you should be able to see what it expects. 如果你看一下方法定义(在Laravel的核心中),你应该能够看到它的期望。

public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)

This currently isn't supported yet by Laravel 5.1's post, patch, put, delete's convenience methods though. 目前这不是由Laravel 5.1的帖子,补丁,把支持,删除的便利方法虽然。

This is addition is currently being discussed here and here . 目前正在这里这里讨论这个补充。

EDIT: I should state that this answered is based on a Laravel 5.1 install, so it might not be 100% applicable to you if you're on an older version. 编辑:我应该声明这个回答基于Laravel 5.1安装,所以如果您使用的是旧版本,它可能不是100%适用于您。

You can use the json method described here: 您可以使用此处描述的json方法:

https://laravel.com/api/5.1/Illuminate/Foundation/Testing/TestCase.html#method_json https://laravel.com/api/5.1/Illuminate/Foundation/Testing/TestCase.html#method_json

AS you can see the third parameter is an array of data witch in this case will be passed to the body of the request as json, and if you need to pass extra headers you can passed them as an array in the fourth parameter. 你可以看到第三个参数是一个数据数组,在这种情况下,它将作为json传递给请求体,如果需要传递额外的头,你可以将它们作为数组传递给第四个参数。

Example: (Inside your test class) 示例:(在您的测试类中)

public function testRequestWithJSONBody()
{
    $this->json(
            'POST', //Method
            '/', //Route
            ['key1' => 'value1', 'key2' => 'value2'], //JSON Body request
            ['headerKey1' => 'headerValue1','headerKey2' => 'headerValue2'] // Extra headers (optional)
        )->seeStatusCode(200);
}

Hope this helps others. 希望这有助于其他人。

With Laravel 5.1 it's easy to send JSON, just pass a regular PHP array and it'll be encoded automatically. 使用Laravel 5.1,可以轻松发送JSON,只需传递常规PHP数组,它就会自动编码。 Example from the docs: 来自文档的示例:

$this->post('/user', ['name' => 'Sally'])
         ->seeJson([
            'created' => true,
         ]);

From the docs: http://laravel.com/docs/5.1/testing#testing-json-apis 来自文档: http//laravel.com/docs/5.1/testing#testing-json-apis

You could override the post method in CrawlerTrait: https://laravel.com/api/5.1/Illuminate/Foundation/Testing/CrawlerTrait.html 您可以覆盖CrawlerTrait中的post方法: https ://laravel.com/api/5.1/Illuminate/Foundation/Testing/CrawlerTrait.html

Or create a new helper method like the following that accepts one extra optional argument: rawContent 或者创建一个新的辅助方法,如下所示,它接受一个额外的可选参数: rawContent

public function postRawContent($uri, array $data = [], array $headers = [], $rawContent = null)
{
    $server = $this->transformHeadersToServerVars($headers);

    $this->call('POST', $uri, $data, [], [], $server, $rawContent);

    return $this;
}

I wanted to test JSON being posted from the browser to the back end. 我想测试从浏览器发布到后端的JSON。 I wanted to put the raw json in phpunit so I did not have to recode the array, which introduced errors. 我想把原始的json放在phpunit中,所以我没有重新编码引入错误的数组。

To do this I first converted the json object to a string in javascript (browser or client) and dumped it to the log: 为此,我首先将json对象转换为javascript(浏览器或客户端)中的字符串并将其转储到日志中:

console.log(JSON.stringify(post_data))

Next I copied and pasted that into phpunit test, then decoded it to an array. 接下来,我将其复制并粘贴到phpunit test中,然后将其解码为数组。 Then I simply sent that array to json: 然后我只是将该数组发送到json:

$rawContent = '{"search_fields":{"vendor_table_id":"123","vendor_table_name":"","vendor_table_account_number":"","vendor_table_active":"null"},"table_name":"vendor_table"}';

$this->json('POST', '/vendors', json_decode($rawContent, true))
     ->seeJson([
            'id' => 123,
        ]);

This was the only way it worked for me after implementing the other answers to this post, so I thought I would share. 在实现这篇文章的其他答案之后,这是它对我有用的唯一方式,所以我想我会分享。 I am using laravel 5. 我正在使用laravel 5。

after some work around I fixed and I have it done. 经过一些努力我修好了,我完成了。



    $response = $this->call(
                'POST',
                "{$this->baseUrl}/{$this->version}/companies/{$company->id}",
                [
                    'name' => 'XPTO NAME',
                    'email' => 'xpto@example.org'
                ],
                [],
                [
                    'logo_image' => UploadedFile::fake()->image('teste.jpg', 200, 200),
                    'cover' => UploadedFile::fake()->image('teste.jpg', 1600, 570)
                ],
                [
                    'CONTENT_TYPE' => HttpContentType::MULTIPART_FORM_DATA,
                    'HTTP_ACCEPT' => HttpContentType::MULTIPART_FORM_DATA,
                    'HTTP_X_YOUR_TOKEN' => $authToken->token
                ]
            );
            $response->assertStatus(HttpStatusCodes::OK);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM