当有附加参数时,模拟模型绑定失败

Posted

技术标签:

【中文标题】当有附加参数时,模拟模型绑定失败【英文标题】:Mocking model bindings fails when there are additional parameters 【发布时间】:2018-09-29 17:19:06 【问题描述】:

我正在使用 Laravel 的 browserkit 测试来测试我的应用中的路由。

路由定义为:

web.php

Route::post("myroute/mymodel", "MyController@viewMyModel");

路由服务提供者

Route::model("mymodel", MyModel::class); 

我的控制器

public function viewMyModel(Request $req, MyModel $myModel, $parameter) 
   //Does things

我现在需要测试给定 MyModel 特定实例的行为

我的测试用例是:

public function testDoesThingsWithoutFailing() 
    $this->withoutMiddleware();
    $this->app->instance(MyModel::class, $this->getMockBuilder(MyModel::class)->getMock());        
    $urlToVisit = url()->action("ReportsController@saveComponentAs", [
        "mymodel" => 123, "parameter" => "p"
    ]);
    $this->call("POST", $urlToVisit);
    $this->assertResponseStatus(200);

当我这样做时它失败了,因为“mymodel”作为控制器的 3 参数传递,因为第二个参数是从容器中注入的,即当我在 viewMyModel 内执行 func_get_args 时,我得到:

array:4 [
0 => Illuminate\Http\Request ...
1 => Mock_MyModel_6639c39c ...
2 => "123"
3 => "p"
]

这是错误的(但在意料之中),因为参数 2 现在被注入而不是被路由绑定替换。

但是当我尝试时

$urlToVisit = url()->action("ReportsController@saveComponentAs", [
     "parameter" => "p"
]);

我明白了

UrlGenerationException : [Route: ] 缺少必需的参数

在理想情况下,我不需要使用$this->withoutMiddleware(),但我现在需要这样做,因为如果我不这样做,模型似乎会正常解析,而不是通过容器解析。

我在这里做错了吗?我错过了什么明显的东西吗?

【问题讨论】:

路由它期待一个您没有提供的mymodel 参数,如果您将路由参数更改为parameter @LeoinstanceofKelmendi 这就是问题所在。我确实在我的测试的第一个实例中提供了它,但是我得到了 123 作为 $parameter 传递的第四个参数,值为 "p" .. 基本上它被移动了一个位置(我在分享时注意到了这一点测试用例) 我怀疑它可能是一个框架错误!不过我会在下班后研究它!看起来很有趣的错误。 @LeoinstanceofKelmendi 我想我发现我在这里做错了。 ***.com/questions/46354412/… 就是答案。我通过禁用中间件和使用容器绑定来禁用模型绑定,但这是不正确的。我需要保留和模拟模型绑定。我会尽快回复的 【参考方案1】:

https://***.com/a/46364768/487813 的这个答案让我找到了正确的解决方案。

问题:

我禁用了禁用路由绑定的中间件,这是故意的,因为我认为我需要这个。然而,这使得框架注入模型而不是用模型替换参数。在所有注入的模型之后,该参数最终被添加到请求中。

解决办法:

继续使用模型绑定,但模拟绑定结果。以下是有效的:

public function testDoesThingsWithoutFailing() 
    // Need the middleware to run
    $this->app->get('router')->bind(MyModel::class, function ()  
         return $this->getMockBuilder(MyModel::class)->getMock(); 
    ); 
    $urlToVisit = url()->action("ReportsController@saveComponentAs", [
        "mymodel" => 123, "parameter" => "p"
    ]);
    $this->call("POST", $urlToVisit);
    $this->assertResponseStatus(200); //Works as expected

【讨论】:

以上是关于当有附加参数时,模拟模型绑定失败的主要内容,如果未能解决你的问题,请参考以下文章

顺序模型中层的附加参数

附加函数具有绑定时删除侦听器

带有附加参数的 Django 自定义模型方法

在代码中绑定到可绑定的附加属性

vs2022创建模拟器失败

通过附加原始文件名保存文件