我正在尝试对Stripe webhook处理程序的实现进行单元测试。条带webhook数据作为POST请求正文中的原始JSON在线上传播,因此我捕获并解码数据:
public function store()
{
$input = @file_get_contents("php://input");
$request = json_decode($input);
return Json::encode($request);
}
我试图对此代码进行单元测试,但我无法弄清楚如何在单元测试中发送原始JSON数据,以便我可以使用file_get_contents("php:input//")
函数检索它。这是我尝试过的(使用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?
}
我也试过了curl
,但这会产生一个外部请求,从单元测试的角度来看,这对我没有意义。如何使用我的store
方法获取的正文中的原始JSON数据来模拟POST请求?
答案 0 :(得分:6)
你可以。但是你需要发送编码的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'])
);
这是第7个参数。
如果你看一下方法定义(在Laravel的核心中),你应该能够看到它的期望。
public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
目前,Laravel 5.1的帖子,补丁,放置,删除等便捷方法目前尚不支持 。
编辑:我应该声明此答案是基于Laravel 5.1安装的,因此如果您使用的是旧版本,则可能不会100%适用。
答案 1 :(得分:3)
您可以使用此处描述的json
方法:
https://laravel.com/api/5.1/Illuminate/Foundation/Testing/TestCase.html#method_json
你可以看到第三个参数是一个数据数组,在这种情况下,它将作为json传递给请求体,如果需要传递额外的头,你可以在第四个参数中将它们作为数组传递
实施例: (在测试课程内)
public function testRequestWithJSONBody()
{
$this->json(
'POST', //Method
'/', //Route
['key1' => 'value1', 'key2' => 'value2'], //JSON Body request
['headerKey1' => 'headerValue1','headerKey2' => 'headerValue2'] // Extra headers (optional)
)->seeStatusCode(200);
}
希望这有助于其他人。
答案 2 :(得分:0)
使用Laravel 5.1,它很容易发送JSON,只需传递一个常规的PHP数组,它就会被自动编码。来自文档的示例:
$this->post('/user', ['name' => 'Sally'])
->seeJson([
'created' => true,
]);
答案 3 :(得分:0)
您可以覆盖CrawlerTrait中的post方法: https://laravel.com/api/5.1/Illuminate/Foundation/Testing/CrawlerTrait.html
或者创建一个新的辅助方法,如下所示,它接受一个额外的可选参数:rawContent
public function postRawContent($uri, array $data = [], array $headers = [], $rawContent = null)
{
$server = $this->transformHeadersToServerVars($headers);
$this->call('POST', $uri, $data, [], [], $server, $rawContent);
return $this;
}
答案 4 :(得分:0)
我想测试从浏览器发布到后端的JSON。我想把原始的json放在phpunit中,所以我没有重新编码引入错误的数组。
为此,我首先将json对象转换为javascript(浏览器或客户端)中的字符串并将其转储到日志中:
console.log(JSON.stringify(post_data))
接下来,我将其复制并粘贴到phpunit测试中,然后将其解码为数组。然后我只是将该数组发送到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,
]);
在实现这篇文章的其他答案之后,这是它对我有用的唯一方式,所以我想我会分享。我正在使用laravel 5.
答案 5 :(得分:0)
$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);