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

时间:2013-11-20 10:52:20

标签: laravel laravel-4

更新见下文

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

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

5 个答案:

答案 0 :(得分:14)

您需要在实际标头前加上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');
}

答案 1 :(得分:5)

这是Laravel 5.2的解决方案。

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

就这么简单。

最初,json方法适用于以下标题:

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

答案 2 :(得分: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'],
    ]);

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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