在 PHPUnit 中调用路由时如何在 Laravel 8 中模拟 Eloquent 模型
Posted
技术标签:
【中文标题】在 PHPUnit 中调用路由时如何在 Laravel 8 中模拟 Eloquent 模型【英文标题】:How to mock Eloquent Model in Laravel 8 when calling a route in PHPUnit 【发布时间】:2021-09-14 04:40:25 【问题描述】:我正在尝试在模型中模拟一个方法,以便能够在不同的场景下测试控制器 api 端点。
我目前正在使用带有 phpUnit 和 Mockery 包的 Laravel 8。 在路由中我使用的是Route模型绑定。
api.php
Route::get('/api/project', [ProjectController::class, 'show']);
ProjectController.php
class ProjectController extends Controller
public function show(Project $project)
$state = $project->getState();
return response()->json($state);
ProjectControllerTest.php
class ProjectControllerTest extends TestCase
/**
* @test
* @group ProjectController
*/
public function shouldReturn200ForValidProjectGuid()
$project = Project::factory()->create();
$mock = Mockery::mock(Project::class);
// I have also tried this, see error below
// $mock = Mockery::mock(Project::class)->makePartial();
$this->app->instance(Project::class, $mock);
$mock->shouldReceive('getState')->andReturn('New South Wales');
$response = $this->getJson("/api/$project->guid");
$response->assertStatus(200)
->assertJson([
'data' => 'New South Wales'
]);
我目前收到此错误
Received Mockery_0_App_Models_Project::resolveRouteBinding(), but no expectations were specified Exception caught at [/usr/src/app/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34) : eval()'d code@924
我已经尝试了其他选项,例如 makePartial(),但是它也会导致以下错误
Received Mockery_0_App_Models_Project::__construct(), but no expectations were specified Exception caught at [/usr/src/app/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34) : eval()'d code@924
任何帮助将不胜感激,谢谢
【问题讨论】:
为什么不使用标准模拟 phpunit $stub = $this->createMock(SomeClass::class) ? @АлександрЧерножуков 我试过用它,但还是不行,你能提供一个例子吗 我读到了在mock上调用resolveRouteBinding
方法的错误信息,但是mock不知道如何处理这个调用,因此抛出了异常。在让系统使用模拟之前,实际指定这个缺失的期望会有所帮助。
@hakre 你能提供一个例子吗
【参考方案1】:
您可以尝试以下方法。我稍微更改了控制器响应以使其与assertJson()
一起使用。
web.php
Route::get('/projects/project', [ProjectController::class, 'show']);
项目控制器
<?php
namespace App\Http\Controllers;
use App\Models\Project;
class ProjectController extends Controller
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Project $project)
return response()->json([
'state' => $project->getState()
]);
ProjectControllerTest
<?php
namespace Tests\Feature;
use App\Models\Project;
use Mockery;
use Tests\TestCase;
class ProjectControllerTest extends TestCase
/**
* A basic test example.
*
* @return void
*/
public function test_example()
$mock = Mockery::mock(Project::class)->makePartial();
$mock->shouldReceive('resolveRouteBinding')->andReturnSelf();
$mock->shouldReceive('getState')->andReturn('NSW');
$this->app->instance(Project::class, $mock);
$response = $this->get('/projects/1');
$response->assertStatus(200)
->assertJson([
'state' => 'NSW'
]);
【讨论】:
这不是一个有效的答案,因为您没有模拟模型......但无论如何......【参考方案2】:你没有模拟模型,你已经在使用Factory
,所以你仍然使用它在你的模型上创建“模拟”数据。
$project = Project::factory()->create(['state' => 'New South Wales']);
阅读有关 Laravel 中的工厂和单元测试的更多信息。请参阅官方文档。
【讨论】:
状态不是项目模型的一部分,这是模型中调用的外部数据库,我只想模拟该方法以返回不同的东西。否则我会改用工厂 好吧,所以你还是不模拟一个模型,你模拟模型里面的东西,你能显示模型代码吗?以上是关于在 PHPUnit 中调用路由时如何在 Laravel 8 中模拟 Eloquent 模型的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Laravel 中的 PHPUnit 不能访问存在的路由?
如何在 laravel 5.5 中使用 phpunit 测试中间件?
Laravel 路由仅在 phpunit 测试期间返回 302 而不是 404 响应