模拟
简介
在测试 Laravel 应用程序时,你可能希望「模拟」应用程序的某些方面,以便它们在给定测试期间不会实际执行。例如,在测试分发事件的控制器时,你可能希望模拟事件监听器,以便它们在测试期间不会实际执行。这允许你只测试控制器的 HTTP 响应,而不必担心事件监听器的执行,因为事件监听器可以在它们自己的测试用例中测试。
Laravel 为模拟事件、任务和其他门面提供了开箱即用的有用方法。这些辅助函数主要在 Mockery 之上提供了一个便利层,因此你不必手动进行复杂的 Mockery 方法调用。
模拟对象
当模拟将通过 Laravel 服务容器注入到应用程序中的对象时,你需要将模拟实例作为 instance 绑定绑定到容器中。这将指示容器使用对象的模拟实例而不是构造对象本身:
php
use App\Service;
use Mockery;
use Mockery\MockInterface;
test('可以模拟某些东西', function () {
$this->instance(
Service::class,
Mockery::mock(Service::class, function (MockInterface $mock) {
$mock->expects('process');
})
);
});php
use App\Service;
use Mockery;
use Mockery\MockInterface;
public function test_something_can_be_mocked(): void
{
$this->instance(
Service::class,
Mockery::mock(Service::class, function (MockInterface $mock) {
$mock->expects('process');
})
);
}为了使这更方便,你可以使用 Laravel 基础测试用例类提供的 mock 方法。例如,以下示例等同于上面的示例:
php
use App\Service;
use Mockery\MockInterface;
$mock = $this->mock(Service::class, function (MockInterface $mock) {
$mock->expects('process');
});当你只需要模拟对象的几个方法时,可以使用 partialMock 方法。未模拟的方法在调用时将正常执行:
php
use App\Service;
use Mockery\MockInterface;
$mock = $this->partialMock(Service::class, function (MockInterface $mock) {
$mock->expects('process');
});同样,如果你想监视对象,Laravel 基础测试用例类提供了 spy 方法作为 Mockery::spy 方法的便捷包装器。间谍类似于模拟;但是,间谍记录间谍与被测试代码之间的任何交互,允许你在代码执行后进行断言:
php
use App\Service;
$spy = $this->spy(Service::class);
// ...
$spy->shouldHaveReceived('process');模拟门面
与传统静态方法调用不同,门面(包括实时门面)可以被模拟。这比传统静态方法提供了巨大优势,并为你提供与传统依赖注入相同的可测试性。在测试时,你可能经常希望模拟控制器中发生的 Laravel 门面调用。例如,考虑以下控制器操作:
php
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**