Lumen / Laravel:无法弄清楚如何对json响应进行单元测试

时间:2018-07-11 20:11:31

标签: php laravel unit-testing lumen

我不知道单元测试的工作原理。

我有一个返回JSON响应的控制器

Controller.php

public function getDiscount(Request $request)
{
    if (isset($request) && !empty($request)) {
        return response()->json($this->discount->calculateDiscount($request->json()->all()))->getOriginalContent();
    }
}

对于邮递员,这是此路线的结果:

由客户发布:

{
  "customer-id": "3",
  "items": [
    {
      "product-id": "A101",
      "quantity": "2",
      "unit-price": "9.75",
      "total": "19.50"
    },
    {
      "product-id": "A102",
      "quantity": "1",
      "unit-price": "49.50",
      "total": "49.50"
    }
  ],
  "total": "69.00"
}

通过API响应

{
    "applied_discounts": [
        {
            "id": 3,
            "name": "Tools Discount",
            "description": "Seems like you really like Tools, here's one for free!"
        }
    ],
    "discounted_items": [
        {
            "product-id": "A101",
            "quantity": "2",
            "unit-price": "9.75",
            "total": "19.50",
            "discounted_price": 15.6
        }
    ],
    "discounted_price": 65.1,
    "original_price": "69.00"
}

现在,当我尝试进行单元测试时,这就是我想到的:

public function testToolsDiscount()
{
    $this->json('POST', '/discount',
        [
            'customer-id' => '3',
            'items' => [
                [
                    'product-id' => 'A101',
                    'quantity' => '2',
                    'unit-price' => '9.75',
                    'total' => '19.50'
                ],
                [
                'product-id' => 'A102',
                'quantity' => '1',
                'unit-price' => '49.50',
                'total' => '49.50'
                ]
            ],
            'total' => '69.00'
        ])
        ->seeJson(
            [
            'applied_discounts' => [
                [
                    'id' => 3,
                ]
            ],
        ]);
}

但是,当我运行它时,这是我得到的错误

  

DiscountTest :: testToolsDiscount从返回了无效的JSON   路线。也许引发了异常?

我在做什么错了?

3 个答案:

答案 0 :(得分:2)

确保您的路线与指定的'/discount'匹配,且可能带有前缀。

答案 1 :(得分:0)

定义正确的路线,

我建议使用action()辅助功能来添加url,该功能的主要好处是当您更改路线中的某些文本或前缀时, 假设您将/discount更改为/discounts,在这种情况下,无需到处更改路线。

action('ControllerName@actionName');

答案 2 :(得分:-1)

您的后主体可能需要是实际的JSON字符串,而不是关联数组。 json()方法也可能需要完全限定的URL而不是相对路径。如果是这种情况,则此解决方案可能实际上无法解决问题,您只需尝试一下即可查看。否则,请尝试此操作,它至少应提供一些有关出问题的线索。将以下内容添加到您的单元测试类中,并dd()将结果添加到

/**
 * @param string $uri
 * @param string $method
 * @param array $body
 * @param array $headers
 * @param array $files
 * @param array $cookies
 * @return array
 */
public function callRoute(
    $uri,
    $method = 'GET',
    array $body = [],
    array $headers = [],
    array $files = [],
    array $cookies = []
) {
    foreach ($cookies as $name => $cookie) {
        $this->app->resolving(\App\Http\Middleware\EncryptCookies::class, function (\App\Http\Middleware\EncryptCookies $cookie) use ($name) {
            $cookie->disableFor($name);
        });
    }

    $uri = trim($uri, '/');
    $uriParts = parse_url($uri);
    //This value may be based on the APP_URL value in your .env, I'm not really sure.
    $root = !array_get($uriParts, 'host') ? trim(app(\Illuminate\Http\Request::class)->root(), '/').'/' : '';
    $uri = "$root$uri";
    $server = $this->transformHeadersToServerVars($headers);
    $response = $this->call($method, $uri, $body, $cookies, $files, $server);

    $headers = $response->headers->all();
    $code = $response->getStatusCode();
    $json = $content = $response->getContent();
    $json = json_decode($json, true);
    $content = ($json && json_last_error() == JSON_ERROR_NONE) ? $json : $content;

    return compact('code', 'headers', 'content');
}

我愿意打赌,以下内容将显示错误消息和堆栈跟踪。您可能必须在目标控制器中继续执行其他一些dd()语句,或者在该错误指示您向正确的方向之后,逻辑仍然生活在其他任何地方:

$body = [
    'customer-id' => '3',
    'items' => [
        [
            'product-id' => 'A101',
            'quantity' => '2',
            'unit-price' => '9.75',
            'total' => '19.50'
        ],
        [
            'product-id' => 'A102',
            'quantity' => '1',
            'unit-price' => '49.50',
            'total' => '49.50'
        ]
    ],
    'total' => '69.00'
];

$response = $this->callRoute('POST', '/discount', $body)['content'];
dd($response);