Skip to content

Mocking

Nguồn gốc: Bản dịch từ Mocking

Giới thiệu (Introduction)

Khi test, bạn có thể muốn "mock" một số phần của ứng dụng để chúng không thực sự thực thi. Ví dụ: test controller dispatch event → mock event listener để không thực thi → chỉ test HTTP response của controller.

Laravel cung cấp helper methods cho mocking events, jobs, facades. Chúng là convenience layer trên Mockery.

Mocking Objects

Mock object inject vào container:

php
use App\Service;
use Mockery;
use Mockery\MockInterface;

test('something can be mocked', 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');
        })
    );
}

Shortcut tiện lợi với $this->mock():

php
use App\Service;
use Mockery\MockInterface;

$mock = $this->mock(Service::class, function (MockInterface $mock) {
    $mock->expects('process');
});

Partial Mock

php
$mock = $this->partialMock(Service::class, function (MockInterface $mock) {
    $mock->expects('process');
});

Method không được mock → thực thi bình thường.

Spies

php
use App\Service;

$spy = $this->spy(Service::class);

// Code thực thi...

$spy->shouldHaveReceived('process');

Mocking Facades

Facades có thể mock — ưu điểm lớn so với static methods truyền thống:

php
use Illuminate\Support\Facades\Cache;

test('get index', function () {
    Cache::expects('get')
        ->with('key')
        ->andReturn('value');

    $response = $this->get('/users');
    // ...
});
php
use Illuminate\Support\Facades\Cache;
use Tests\TestCase;

class UserControllerTest extends TestCase
{
    public function test_get_index(): void
    {
        Cache::expects('get')
            ->with('key')
            ->andReturn('value');

        $response = $this->get('/users');
        // ...
    }
}

LƯU Ý

Không mock Request facade — thay vào đó dùng get, post trong test. Không mock Config facade — gọi Config::set() trực tiếp.

Facade Spies

php
use Illuminate\Support\Facades\Cache;

Cache::spy();

$response = $this->get('/');

Cache::shouldHaveReceived('put')->once()->with('name', 'Taylor', 10);

Tương tác với Time

Laravel cho phép thay đổi thời gian hiện tại trong test:

php
// Du hành đến tương lai
$this->travel(5)->milliseconds();
$this->travel(5)->seconds();
$this->travel(5)->minutes();
$this->travel(5)->hours();
$this->travel(5)->days();
$this->travel(5)->weeks();
$this->travel(5)->years();

// Du hành về quá khứ
$this->travel(-5)->hours();

// Đến thời điểm cụ thể
$this->travelTo(now()->subHours(6));

// Quay về thời gian thực
$this->travelBack();

Freeze thời gian:

php
$this->freezeTime();

$this->freezeSecond();