如何在 Laravel 测试用例中模拟 xmlHttpRequests?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20093897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 08:40:27  来源:igfitidea点击:

How to simulate xmlHttpRequests in a laravel testcase?

laravellaravel-4

提问by Oliver Schupp

Updates see below

更新见下文

My controllers distinguish between ajax and other requests (using Request::ajax()as a condition). That works quite fine but I wonder if there is a way of unit testing the controllers handling the the requests. How should a test look like? Something like this probably but it doesn't work ...

我的控制器区分 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'
                    )
                ));


            }
        }

Update

更新

I kind of found a solution. Maybe. Since I am not interested in testing the proper functionality of the Request class (very likely all native classes provided by Laravel, Symfony, etc. are enough unit tested already) best way might be to mock its ajax method. Like this:

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

        public function testShowUser()
        {

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

Because the real Requestclass and not its mocked substitute is used when using the callmethod of the Testcaseclass I had to instantiate the method which is called when the specified route is entered by hand. But I think that is okay because I just want to control that the expressions inside the Request::ajax()condition work as expected with this test.

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

回答by Andreas

You need to prefix the actual header with HTTP_, no need to use HTTP_CUSTOM:

您需要使用 HTTP_ 前缀实际标头,无需使用 HTTP_CUSTOM:

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

Alternative syntax which looks a bit better IMO:

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

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

Here are some similar code examples for JSON headers (Request::isJson()and Request::wantsJson()):

以下是 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');

Here's a useful helper method you can put in your 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');
}

回答by Yauheni Prakopchyk

Here's the solution for Laravel 5.2.

这是 Laravel 5.2 的解决方案。

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

It's that simple.

就这么简单。



Intenally, jsonmethod applies following headers:

在内部,json方法应用以下标题:

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

回答by mopo922

In Laravel 5:

在 Laravel 5 中:

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

Then you can chain the normal assertions:

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

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

回答by chickenchilli

$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);   

回答by chebaby

Laravel 5.X

Laravel 5.X

As an addition to already existing answers, and for claritypurpose you can add those helper methods to your TestCase

作为对现有答案的补充,为了清楚起见,您可以将这些辅助方法添加到您的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']);
    }
}


Usage

用法

<?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,
            ]);
    }
}