【问题标题】:Lumen / Laravel: Can't figure out how unittesting a json response worksLumen / Laravel:无法弄清楚对 json 响应进行单元测试的工作原理
【发布时间】:2018-12-19 23:16:51
【问题描述】:

我不知道单元测试是如何工作的。

我有一个返回 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 从 路线。也许抛出了异常?

我做错了什么?

【问题讨论】:

  • 您定义了任何中间件吗?
  • @FelippeDuarte Nope
  • 运行测试的时候,可以在return里面getDiscount函数之前做一个dd(response()->json($this->discount->calculateDiscount($request->json()->all()))->getOriginalContent());吗?
  • @FelippeDuarte 嗯,我的测试没有任何变化,仍然是相同的输出。但是我刚刚注意到这个Element 'phpunit', attribute 'syntaxCheck': The attribute 'syntaxCheck' is not allowed. 不确定它是否与测试本身有关
  • 你能告诉我们你定义路线的地方吗?

标签: php laravel unit-testing lumen


【解决方案1】:

定义正确的路线,

我推荐使用action()Helper函数来添加url,这个函数的主要好处是当你在路由中改变一些文本或前缀时, 假设您从 /discount 更改为 /discounts 在这种情况下,您不需要到处更改路线。

action('ControllerName@actionName');

【讨论】:

    【解决方案2】:

    确保您的路由与指定的 '/discount' 匹配,并带有它可能具有的任何前缀。

    【讨论】:

      【解决方案3】:

      您的 post-body 可能需要是一个实际的 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);
      

      【讨论】:

      • 不猜测正确的解决方案与提供错误的答案不同。根据接受的答案,我可以说,如果您按照我的说明进行操作,您会注意到解析测试响应的 code 部分会显示 404,这是 URI 错误的提示。我不介意你没有选择我的答案,但你能解释一下否决票吗?
      猜你喜欢
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      • 2023-03-19
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多