【问题标题】:Testing laravel controllers with JSON request body使用 JSON 请求正文测试 laravel 控制器
【发布时间】:2012-12-19 18:11:09
【问题描述】:

我正在尝试为 Laravel 控制器编写一个 phpunit 测试,该控制器需要带有 JSON 格式正文的 post 请求。

控制器的简化版本:

class Account_Controller extends Base_Controller
{
    public $restful = true;

    public function post_login()
    {
        $credentials = Input::json();
        return json_encode(array(
            'email' => $credentials->email,
            'session' => 'random_session_key'
        ));
    }
}

目前我有一个测试方法可以正确地将数据作为 urlencoded 表单数据发送,但我不知道如何将数据作为 JSON 发送。

我的测试方法(我在写测试时使用了github gisthere

class AccountControllerTest extends PHPUnit_Framework_TestCase {
    public function testLogin()
    {
        $post_data = array(
            'email' => 'user@example.com',
            'password' => 'example_password'
        );
        Request::foundation()->server->set('REQUEST_METHOD', 'POST');
        Request::foundation()->request->add($post_data);
        $response = Controller::call('account@login', $post_data);
        //check the $response
    }
}

我在前端使用 angularjs,默认情况下,发送到服务器的请求是 JSON 格式。我不希望将其更改为发送 urlencoded 表单。

有谁知道我如何编写一个为控制器提供 JSON 编码主体的测试方法?

【问题讨论】:

    标签: angularjs laravel phpunit laravel-3


    【解决方案1】:

    至少从 Laravel 5.2 开始,Illuminate\Foundation\Testing\Concerns\MakesHttpRequests 中有一个 json() 方法,因此您可以执行以下操作:

    $data = [
      "name" => "Foobar"
    ];
    $response = $this->json('POST', '/endpoint', $data);
    

    此外,从 Laravel 5.3 开始,还有 putJson()postJson() 等方便的方法。因此它甚至可以进一步缩短为:

    $data = [
      "name" => "Foobar"
    ];
    $response = $this->postJson('/endpooint', $data);
    

    然后你可以像$response->assertJson(...)一样:

    $response->assertJson(fn (AssertableJson $json) => $json->hasAll(['id', 'name']));
    

    【讨论】:

      【解决方案2】:

      从 Laravel 5.1 开始,有一种更简单的方法可以通过 PHPunit 测试 JSON 控制器。只需传递一个包含数据的数组,它就会自动编码。

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

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

      【讨论】:

      • 我认为这不会使请求本身具有 application/json 的内容类型标头。据我所知,它仍会将 application/x-www-form-urlencoded 发送到 /users 端点。我相信用 json 强制请求的方法是做@eoinoc 所做的事情。
      • 使用 $this->json('POST', ... 而不是 $this->post(... 来使用适当的内容类型。
      【解决方案3】:

      在 Laravel 5 中,call() 方法发生了变化:

      $this->call(
          'PUT', 
          $url, 
          [], 
          [], 
          [], 
          ['CONTENT_TYPE' => 'application/json'],
          json_encode($data_array)
      );
      

      我认为 Symphony 的 request() 方法正在被调用: http://symfony.com/doc/current/book/testing.html

      【讨论】:

        【解决方案4】:

        这对我有用。

        $postData = array('foo' => 'bar');
        $postRequest = $this->action('POST', 'MyController@myaction', array(), array(), array(), array(), json_encode($postData));
        $this->assertTrue($this->client->getResponse()->isOk());
        

        $this->action 的第七个参数是content。请参阅http://laravel.com/api/source-class-Illuminate.Foundation.Testing.TestCase.html#_action 的文档

        【讨论】:

        • 我也在寻找解决方案,在the docs找到相同的答案。
        • 好答案,但请确保将 json 传递给第 6 个参数,而不是第 7 个。
        【解决方案5】:

        这就是我在 Laravel4 中执行此操作的方式

        // Now Up-vote something with id 53
        $this->client->request('POST', '/api/1.0/something/53/rating', array('rating' => 1) );
        
        // I hope we always get a 200 OK
        $this->assertTrue($this->client->getResponse()->isOk());
        
        // Get the response and decode it
        $jsonResponse = $this->client->getResponse()->getContent();
        $responseData = json_decode($jsonResponse);
        

        $responseData 将是一个等于 json 响应的 PHP 对象,并允许您随后测试响应:)

        【讨论】:

          【解决方案6】:

          有很多更简单的方法可以做到这一点。您可以简单地将 Input::$json 属性设置为要作为 post 参数发送的对象。请参阅下面的示例代码

           $data = array(
                  'name' => 'sample name',
                  'email' => 'abc@yahoo.com',
           );
          
           Input::$json = (object)$data;
          
           Request::setMethod('POST');
           $response = Controller::call('client@create');
           $this->assertNotNull($response);
           $this->assertEquals(200, $response->status());
          

          我希望这对您的测试用例有所帮助

          更新:原始文章可在此处获得http://forums.laravel.io/viewtopic.php?id=2521

          【讨论】:

          • 我有机会使用这种方法重写我的一些测试。我发现它更有用,因为它允许我检查单个代码是否在工作,而不是检查用于 http 请求的所有代码。当出现问题时,此方法还提供回溯,这在调试时比 http 状态代码更有用。
          • 当我尝试这个时,我得到Fatal error: Access to undeclared static property: Illuminate\Support\Facades\Input::$json - 我错过了一些上下文吗?
          • @AaronPollock 因为 json() 是一种方法,而不是属性。将其用作 Input::json()
          【解决方案7】:

          一个简单的解决方案是使用 CURL - 这样您还可以从服务器捕获“响应”。

          class AccountControllerTest extends PHPUnit_Framework_TestCase
          {
          
           public function testLogin()
           {
              $url = "account/login";
          
              $post_data = array(
                  'email' => 'user@example.com',
                  'password' => 'example_password'
              );
              $content = json_encode($post_data);
          
              $curl = curl_init($url);
              curl_setopt($curl, CURLOPT_HEADER, false);
              curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
              curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
              curl_setopt($curl, CURLOPT_POST, true);
              curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
          
              $json_response = curl_exec($curl);
          
              $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
          
              curl_close($curl);
          
              $response = json_decode($json_response, true);
          
              // Do some $this->Assert() stuff here on the $status
            }
          }
          

          CURL 实际上会使用 JSON 模拟原始 HTTP 帖子 - 所以您知道您正在真正测试您的功能;

          【讨论】:

          • 好方法。但我建议使用Httpful bundle 来保持测试代码更简洁。
          • 我最终创建了一个类,它将所有 curl 功能包装成一些更易于使用的函数并更新我的测试以从新类继承。 ApiTestCase.php
          猜你喜欢
          • 2022-01-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-26
          • 2015-03-12
          • 2020-11-18
          • 1970-01-01
          相关资源
          最近更新 更多