如何在 Laravel 5 包内的测试中模拟 Accept 标头?

How to simulate Accept header in a test within a Laravel 5 package?

提问人:aborted 提问时间:6/30/2016 最后编辑:aborted 更新时间:3/5/2020 访问量:2388

问:

我目前正在构建一个 Laravel 包,该包通过注入了新方法。我注入的方法已经完成,预计效果很好,但我也想在发布之前对其进行测试。Illuminate\Http\Request

我的测试要求我更改请求的标头,以便查看测试是否通过。因此,我做了以下操作来模拟请求:Accept

// package/tests/TestCase.php

namespace Vendor\Package;

use Illuminate\Http\Request;
use Orchestra\Testbench\TestCase as Orchestra;

abstract class TestCase extends Orchestra
{
    /**
     * Holds the request
     * @var Illuminate\Http\Request
     */
    protected $request;

    /**
     * Setup the test
     */
    public function setUp()
    {
        parent::setUp();

        $this->request = Request::capture();

        $this->request->headers->set('Accept', 'application/x-yaml');
    }
}

然后在我的测试中,我使用我注入的方法,它总是返回 false,因为标头没有设置为 .Request$this->request->wantsYaml()Acceptapplication/x-yaml

class RequestTest extends TestCase
{
    /** @test */
    public function it_should_return_a_bool_if_page_wants_yaml_or_not()
    {
        dump($this->request->wantsYaml()); // Return false

        $this->assertTrue($this->request->wantsYaml()); // It fails!
    }
}

如何在 Laravel 包开发中的测试中继续模拟标头?


编辑

这是我的班级YamlRequest

use Illuminate\Http\Request;
use Illuminate\Support\Str;

class YamlRequest extends Request
{
    /**
     * Acceptable content type for YAML.
     * @var array
     */
    protected $contentTypeData = ['/x-yaml', '+x-yaml'];

    /**
     * Determine if the current request is asking for YAML in return.
     *
     * @return bool
     */
    public function wantsYaml()
    {
        $acceptable = $this->getAcceptableContentTypes();

        // If I dd($acceptable), it comes out as empty during tests!

        return isset($acceptable[0]) && Str::contains($acceptable[0], $this->contentTypeData);
    }
}

因此,我实际上必须模拟 Accept,以查看我的方法是否按预期工作。wantsYaml

PHP 测试 laravel-5 phpunit 软件包

评论

0赞 Marcin Nabiałek 7/1/2016
请包括您的类或您想要执行此操作的类部分,以及如何在此类中传递/创建 Request 对象
0赞 aborted 7/1/2016
添加了语句。use
0赞 aborted 7/1/2016
@MarcinNabia łek 你到底指的是哪个班级?我只想模拟测试的 Content-Type 标头。我的代码可以正常工作(我相信),但我需要在我的测试中进行这种模拟来证明它。
0赞 Marcin Nabiałek 7/1/2016
您至少应该包括 - 例如,它如何使用此标头以及它如何返回值myMethod
0赞 aborted 7/1/2016
我用具体的代码完全更新问题。

答:

-1赞 Marcin Nabiałek 7/2/2016 #1

好的,老实说,我不知道您如何在代码中使用它,但我认为这里有 2 个问题:YamlRequest

1)在你的测试中,你创建的是对象而不是对象 - 这是正确的吗?对我来说似乎不是,但也许应该是这样的Illuminate\Http\RequestYamlRequest

2)第二件事是方法的代码。查看您的方法实现,您设置了无效的标头,因为方法获取标头而不是getAcceptableContentTypes()AcceptContent-Type

如果我将测试代码更改为如下所示:

$request = new \App\Http\Requests\YamlRequest();
$request->headers->set('Accept', 'application/x-yaml');
$this->assertTrue($request->wantsYaml()); 

它通过了。但是我不得不使用标题而不是.我认为这是错误。AcceptContent-Type

评论

0赞 aborted 7/2/2016
很抱歉没有像我应该解释的那样解释那部分。我使用一个宏(参见 Laravel 中的 Macroable trait),并通过包的服务提供商注入 YamlRequest,因此我在类中提供了可用的方法。在我的 TestCase 类中,我尝试将标头切换到方法中,但它不起作用。我将更新上面的代码。wantsYaml()RequestAcceptsetUp
0赞 aborted 7/2/2016
另外,请注意,所有这些都发生在一个 laravel 包中,没有真正的“应用程序”部分!
0赞 Kiran Maniya 2/13/2020 #2

如果您使用单元测试来测试应用程序,则有一个预构建的 laravel assertHeader() 和 assertHeaderMissing() 函数可能会对您有所帮助。请参阅此处的官方文档。这是摘自 Docs 的代码片段,

$response->assertHeader($headerName, $value = null);
$response->assertHeaderMissing($headerName);
1赞 Travis Hohl 3/5/2020 #3

一个部分模拟的对象将允许你测试你的,而无需在 Laravel 的对象中测试辅助方法。换句话说,你真正需要知道的是你的宏是否有效。您无需测试是否可以构造 a 以及是否可以设置其标头。Illuminate\Http\Request::macroIlluminate\Http\RequestRequest

在以下测试中,我将使用 Mockery 设置对象的“部分”模拟版本。YamlRequest

当我们只需要模拟一个对象的多个方法时,部分模拟很有用,其余的方法可以自由地正常响应调用(即实现时)。

请参阅模拟文档创建部分模拟

部分模拟将允许我们模拟 Laravel 对象中的方法,同时让您的宏像在生产环境中一样自由运行。Request

use YamlRequest;
use \Mockery;

class RequestTest extends TestCase
{
    public function setUp()
    {
        parent::setUp();

        $this->request = Mockery::mock(YamlRequest::class)->makePartial();
    }

    public function test_that_wants_yaml_returns_true_given_x-yaml_accept_header()
    {
        /**
         *  This line allows you to control the return value of
         *  Illuminate\Http\Request::getAcceptableContentTypes while your macro
         *  is running.
         */
        $this->request->allows(
            [
                'getAcceptableContentTypes' => ['application/x-yaml', 'text/html']
            ]
        );

        $this->assertTrue($this->request->wantsYaml());
    }

    public function test_that_wants_yaml_returns_false_given_json_accept_header()
    {
        $this->request->allows(
            [
                'getAcceptableContentTypes' => ['application/json', 'text/html']
            ]
        );

        $this->assertFalse($this->request->wantsYaml());
    }
}