Laravel PHPUnit模拟请求 [英] Laravel PHPUnit mock Request

查看:45
本文介绍了Laravel PHPUnit模拟请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在控制器上执行PHPUnit,但似乎无法嘲笑请求权限.

这里是控制器:

 使用Illuminate \ Http \ Request;公共功能插入(请求$请求){//...这里有一些代码if($ request-> has('username')){$ userEmail = $ request-> get('username');} else if($ request-> has('email')){$ userEmail = $ request-> get('email');}//...这里有一些代码} 

然后在单元测试中,

 公共函数testIndex(){//...这里有一些代码$ requestParams = ['用户名'=>'测试','email'=>'test@test.com'];$ request = $ this-> getMockBuilder('Illuminate \ Http \ Request')-> disableOriginalConstructor()-> setMethods(['getMethod','retrieveItem','getRealMethod','all','getInputSource','get','has'])-> getMock();$ request->期望($ this-> any())->方法('get')-> willReturn($ requestParams);$ request->期望($ this-> any())->方法('has')-> willReturn($ requestParams);$ request->期望($ this-> any())->方法('all')-> willReturn($ requestParams);//...这里有一些代码} 

这里的问题是,每当我 var_dump($ request-> has('username'); 时,它总是返回 $ requestParams 值,其中整个数组.我希望它应该返回 true ,因为该数组中存在用户名键.

然后,当我删除 $ requestParams 上的用户名键时,它应该返回false,因为它不包含数组上的 username

解决方案

据我所知,您是在告诉单元测试,当您在请求对象上调用$ request-> has()时,它应该返回$ requestParams数组,而不是true或false或其他任何值.

除非您使用方法调用专门检查发送的内容,否则您的模拟实际上并不关心发送的内容,它只会关心被调用的内容.

在用例中,如果可能的话,您可能想探索创建一个空请求并用数据填充它,这将使您更轻松,更少地运行单元测试.这并非在所有情况下都有效.

您可以在单元测试中包含您要进行的断言,以便我们可以更清楚地了解您所遇到的问题,但实际上是这样.它返回的正是您告诉它返回的内容.即使那不是您真正想要的返回值.

模拟用来将单元测试与系统的其余部分分开.因此,您通常通常只检查是否调用了特定方法,以查看您的代码是否实际退出了所模拟的类,以及该类是否具有要发送的预期数据.在某些极端的情况下,您可能希望模拟实际测试的系统,但这通常表明您的代码过于依赖其他类或做得太多.

使用模拟的另一个原因是要在方法调用中满足Type Casting约束.在这种情况下,您通常会创建一个空的模拟对象,并用一些伪数据填充该伪对象,您的代码将接受这些伪数据或破坏该伪数据来测试代码.

在您的情况下,您似乎想检查代码是否真正正确运行,为此,我建议您不要模拟该请求,或者进行特定的测试以告诉它返回true或false(两种情况都进行测试))

所以类似:

  $ request->期望($ this-> any())->方法('has')-> with('用户名')-> willReturn(true);//否则在下一个测试中为false 

正如您在下面的评论中提到的那样,您遇到了在代码中多次使用has方法的问题,并且遇到了问题.

我在响应注释中链接的问题进行了更详细的介绍,但总结起来,您可以使用内联函数或at()方法来处理多种情况.

使用at(),您可以提供代码的特定迭代,以仅实现测试的那一部分.前面已经提到过,这使您的测试相当脆弱,因为以前的测试无法通过之前添加的任何测试.

  $ request-&expects($ this-> at(0))->方法('has')-> with('用户名')-> willReturn('returnValue');$ request->期望($ this-&at; at(1))->方法('has')-> with('email')-> willReturn('otherReturnValue'); 

内联函数(回调)解决方案使您可以自定义测试以允许多种情况并根据需要返回数据.不幸的是,我对这个概念不太熟悉,因为我以前从未使用过它.我建议阅读 PHPUnit文档有关此的更多信息.

最后,我仍然建议不要嘲笑该请求,而是提出一个空请求,您将用要检查的数据填充该请求.Laravel提供了一些令人印象深刻的方法,这些方法可以让您手动填充通常会测试的大量数据.

例如,您可以使用

添加数据(发布/获取数据)

  request-> add(['fieldname'=>'value']) 

作为最后的几个指针,我想提及一下,看来您使用的是var_dump.Laravel自带两个功能,它们在调试中非常相似且非常有用.您可以使用 dd(); dump(); dd(); 转储并停止执行代码,而 dump(); 仅输出您决定的内容.因此您可以执行 dd($ request); dump($ request); 并查看变量/类对象/etc的内容.甚至使用一些Javascript将其放在相当漂亮的布局中,以便您查看其中的内容.如果您不知道它的存在,可能想检查一下.

I'm doing a PHPUnit on my controller and I can't seem to mock the Request right.

Here's the Controller:

use Illuminate\Http\Request;

public function insert(Request $request)
{
    // ... some codes here
    if ($request->has('username')) {
        $userEmail = $request->get('username');
    } else if ($request->has('email')) {
        $userEmail = $request->get('email');
    }
    // ... some codes here
}

Then on the unit test,

public function testIndex()
{
    // ... some codes here

    $requestParams = [
        'username' => 'test',
        'email'    => 'test@test.com'
    ];

    $request = $this->getMockBuilder('Illuminate\Http\Request')
        ->disableOriginalConstructor()
        ->setMethods(['getMethod', 'retrieveItem', 'getRealMethod', 'all', 'getInputSource', 'get', 'has'])
        ->getMock();

    $request->expects($this->any())
        ->method('get')
        ->willReturn($requestParams);

    $request->expects($this->any())
        ->method('has')
        ->willReturn($requestParams);

    $request->expects($this->any())
        ->method('all')
        ->willReturn($requestParams);

    // ... some codes here
}

The problem here is that when ever I var_dump($request->has('username'); it always return the $requestParams value in which is the whole array. I'm expecting that it should return true as the username key exists in the array.

Then when I delete the username key on the $requestParams, it should return false as it does not contain the username key on the array

解决方案

As far as I can see and understand you're telling your unit test that when you call $request->has() on your request object that it should return the $requestParams array, not true or false, or anything else.

Unless you specifically check what is send with a method call your mock doesn't actually care what is send, it just cares that it was called.

You might want to explore creating an empty request and filling it with data if that is possible in your use case as that'll let you run your unit test with more ease and less issues. This won't work in all cases.

You could include what assertions you're making in your unit test so we can see more clearly what you're running into, but as it is. It returns exactly what you're telling it to return. Even if that's not what you actually want it to return.

Mocks are used to separate your Unit-Test from the rest of your system. As such you usually tend to only check if a specific method is called to see if your code actually exits to the class you mocked and if it has the expected data you'd send along. In some extreme cases you can want to mock the system you're actually testing, but this usually indicates that your code is too dependent on other classes or it's doing too much.

Another reason to use mocks is to satisfy Type Casting constraints in your method calls. In these cases you'll usually create an empty mocked object and fill it with some dummy data your code will accept or break on to test the code.

In your case it seems you want to check if your code actually works correctly and for this I'd suggest either not mocking the request, or making specific tests where you tell it to return true, or false (test for both cases)

So something along the lines of:

$request->expects($this->any())
    ->method('has')
    ->with('username')
    ->willReturn(true); // or false in your next test

Edit: As you mentioned in the comment Below you ran into the issue that you're using the has method multiple times in your code and ran into issues.

The Questions I've linked to in my response comment go into greater detail but to sum it up, you can use an inline function or the at() method to deal with multiple cases.

With at() you can supply specific iterations of the code to hit only that bit of the test. It has been mentioned that this makes your tests rather brittle as any has added before the previous ones would break the test.

$request->expects($this->at(0))
    ->method('has')
    ->with('username')
    ->willReturn('returnValue');

$request->expects($this->at(1))
    ->method('has')
    ->with('email')
    ->willReturn('otherReturnValue');

The inline function (callback) solution would allow you to customize your test to allow multiple cases and to return data as required. Unfortunately I'm not too familiar with this concept as I haven't used it myself before. I suggest reading the PHPUnit docs for more information about this.

In the end I'd still suggest not mocking the request and instead making an empty request that you'll fill with the data you want to check. Laravel comes with some impressive methods that'll let you manually fill the request with a lot of data you'd usually test against.

For example you can add data (post/get data) by using

request->add(['fieldname' => 'value'])

As a last few pointers I'd like to mention that it seems you use var_dump. Laravel comes with two of it's own functions that are similar and quite useful in debugging. You can use dd(); or dump(); dd(); dumps and stops the execution of code, while dump(); just outputs whatever you decide. so you could do dd($request); or dump($request); and see what the variables/class objects/etc holds. It'll even put it in a rather spiffy layout with some Javascript and such to allow you to see what's in it and such. Might want to check it out if you didn't knew it existed.

这篇关于Laravel PHPUnit模拟请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆