なおのつぼやき

Webエンジニアです。PHP/Laravel、あとRustを少々

LaravelのDBファサードをモック化してテストを書く

Laravelでユニットテストを書く際にデータベースに依存しないでテストを書いた時に試したやり方をメモしておきます

環境

  • PHP 7.4.8
  • Laravel 7.22.4

確認コード

例えばこんなクラスがありました

<?php

namespace App;

class Book
{
    public function get()
    {
        return \DB::connection('readdb')
            ->table('books')
            ->where('id', 1)
            ->first();
    }
}

以下のような感じでテストメソッドを作成します

<?php

namespace Tests\Unit;

use App\Book;
use Illuminate\Database\Connection;
use Illuminate\Database\Query\Builder;
use Mockery as m;
use Tests\TestCase;

class BookTest extends TestCase
{
    protected function tearDown(): void
    {
        parent::tearDown();
        m::close();
    }

    public function testGet()
    {
        $record = [
            'id' => 1,
            'name' => '名前',
        ];

        $builder = m::mock(Builder::class);
        $builder->shouldReceive('where')->with('id', 1)->andReturn($builder);
        $builder->shouldReceive('first')->andReturn($record);

        $connection = m::mock(Connection::class);
        $connection->shouldReceive('table')->with('books')->andReturn($builder);

        \DB::shouldReceive('connection')->with('readdb')->andReturn($connection);

        $book = new Book();
        $this->assertSame($record, $book->get());
    }
}

参考

recipes.laravel.jp