【问题标题】:How to simulate xmlHttpRequests in a laravel testcase?如何在 laravel 测试用例中模拟 xmlHttpRequests?
【发布时间】:2013-12-04 07:48:03
【问题描述】:

更新见下文

我的控制器区分 ajax 和其他请求(使用 Request::ajax() 作为条件)。这工作得很好,但我想知道是否有一种方法可以对处理请求的控制器进行单元测试。测试应该是什么样子? 可能是这样的,但它不起作用......

<?php

    class UsersControllerTest extends TestCase
        {


            public function testShowUser()
            {
                $userId = 1;
                $response = $this->call('GET', '/users/2/routes', array(), array(), array(
                    'HTTP_CUSTOM' => array(
                        'X-Requested-With' => 'XMLHttpRequest'
                    )
                ));


            }
        }

更新

我找到了一个解决方案。可能是。由于我对测试 Request 类的正确功能不感兴趣(很可能 Laravel、Symfony 等提供的所有本机类都已经进行了足够的单元测试)最好的方法可能是模拟它的 ajax 方法。像这样:

        public function testShowUser()
        {

            $mocked = Request::shouldReceive('ajax')
                ->once()
                ->andReturn(true);
            $controller = new UsersCustomRoutesController;
            $controller->show(2,2);
        }

因为在使用Testcase 类的call 方法时使用的是真正的Request 类而不是它的模拟替代品,所以我必须实例化在手动输入指定路线时调用的方法。但我认为这没关系,因为我只想控制Request::ajax() 条件中的表达式在此测试中按预期工作。

【问题讨论】:

  • 好问题 - the code 用于检测它是否是 AJAX 请求确实只是检查您正在设置的标头。

标签: laravel laravel-4


【解决方案1】:

您需要在实际标头前加上 HTTP_,无需使用 HTTP_CUSTOM:

$server = array('HTTP_X-Requested-With' => 'XMLHttpRequest');
$this->call('get', '/ajax-route', array(), array(), $server);

IMO 看起来更好的替代语法:

$this->client->setServerParameter('HTTP_X-Requested-With', 'XMLHttpRequest');
$this->call('get', '/ajax-route');

以下是 JSON 标头(Request::isJson()Request::wantsJson())的一些类似代码示例:

$this->client->setServerParameter('HTTP_CONTENT_TYPE', 'application/json');
$this->call('get', '/is-json');

$this->client->setServerParameter('HTTP_ACCEPT', 'application/json');
$this->call('get', '/wants-json');

这是一个有用的帮助方法,您可以将其放入您的 TestCase:

protected function prepareAjaxJsonRequest()
{
    $this->client->setServerParameter('HTTP_X-Requested-With', 'XMLHttpRequest');
    $this->client->setServerParameter('HTTP_CONTENT_TYPE', 'application/json');
    $this->client->setServerParameter('HTTP_ACCEPT', 'application/json');
}

【讨论】:

  • 感谢您的回答。我试过了,效果很好。
  • 我无法让$this-&gt;client-&gt;setServerParameter('HTTP_CONTENT_TYPE', 'application/json'); 处理 POST
  • 在这里工作正常,我刚刚在全新安装上进行了测试。
  • 你能把显示你的测试和控制器的代码放在一个 pastebin 里吗?
  • 答案中没有任何内容。使用前面提到的setServerParameterRequest::isJson() 返回 true。
【解决方案2】:

这是 Laravel 5.2 的解决方案。

$this->json('get', '/users/2/routes');

就这么简单。


在本质上,json 方法适用于以下标头:

'CONTENT_LENGTH' => mb_strlen($content, '8bit'),
'CONTENT_TYPE'   => 'application/json',
'Accept'         => 'application/json',

【讨论】:

    【解决方案3】:

    在 Laravel 5 中:

    $this->get('/users/2/routes', ['HTTP_X-Requested-With' => 'XMLHttpRequest']);
    

    然后你可以链接正常的断言:

    $this->get('/users/2/routes', ['HTTP_X-Requested-With' => 'XMLHttpRequest'])
        ->seeJsonStructure([
            '*' => ['id', 'name'],
        ]);
    

    【讨论】:

    • -&gt;assertStatus(302), 302 在这种情况下是一个重定向
    【解决方案4】:
    $server = array('HTTP_X-Requested-With' => 'XMLHttpRequest');
    $request = new \Illuminate\Http\Request($query = array(),$request = array(), $attributes = array(), $cookies = array(), $files = array(), $server , $content = null);   
    

    【讨论】:

      【解决方案5】:

      Laravel 5.X

      作为现有答案的补充,为了清晰目的,您可以将这些辅助方法添加到您的 TestCase

      <?php
      
      namespace Tests;
      
      use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
      
      abstract class TestCase extends BaseTestCase
      {
          use CreatesApplication;
      
          // ...
      
          /**
           * Make ajax POST request
           *
           * @param  string $uri
           * @param  array  $data
           * @return \Illuminate\Foundation\Testing\TestResponse
           */
          public function ajaxPost($uri, array $data = [])
          {
              return $this->post($uri, $data, ['HTTP_X-Requested-With' => 'XMLHttpRequest']);
          }
      
      
          /**
           * Make ajax GET request
           *
           * @param  string $uri
           * @return \Illuminate\Foundation\Testing\TestResponse
           */
          public function ajaxGet($uri)
          {
              return $this->get($uri, ['HTTP_X-Requested-With' => 'XMLHttpRequest']);
          }
      }
      

      用法

      <?php
      
      class ExampleTest extends TestCase
      {
          /**
           * A basic functional test example.
           *
           * @return void
           */
          public function testBasicExample()
          {
              $response = $this->ajaxPost('/user', ['name' => 'Sally']);
      
              $response
                  ->assertStatus(201)
                  ->assertJson([
                      'created' => true,
                  ]);
          }
      }
      

      【讨论】:

        【解决方案6】:

        在 Laravel 8 上,您可以像这样修改标题:

        $response = $this->withHeaders([
                'HTTP_X-Requested-With' => 'XMLHttpRequest',
        ])->get(route('route_name', ['key' => value]));
        

        用 $response 做任何你想做的事。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-11-07
          • 1970-01-01
          • 2019-08-02
          • 2018-11-23
          • 2019-02-08
          • 2018-07-28
          • 2019-08-04
          相关资源
          最近更新 更多