テスト-インメモリDBとモッキング


11

テストを書くとき、誰かがデータをモックするだけでなくインメモリデータベースを使用したいのはなぜですか?

インメモリデータベースは、自分のリポジトリをテストするのに役立つことがわかりました。ただし、フレームワーク(Spring Dataなど)を利用する場合、リポジトリのテストはフレームワークのテストであり、実際にはアプリケーションロジックではありません。

ただし、モッキングはより高速に見え、単体テストやTDDを作成するときに一般的に採用されているのと同じパターンに従っています。

それで私は何が欠けていますか?インメモリデータベースが役立つのはいつ/なぜですか?

回答:


14

モッキングは単体テストの理想的なソリューションであり、統合テストでも速度を向上させるために使用できますが、インメモリデータベースを使用する場合と同じレベルの信頼性はありません。エンドツーエンドのテストを作成して、アプリケーション全体を可能な限り本番環境に近い方法で構成し、それに対して自動テストを実行する必要があります。これらのテストでは、実際のデータベース(インメモリ、Docker、VM、またはその他のデプロイメント)を使用する必要があります。

ただし、フレームワーク(Spring Dataなど)を利用する場合、リポジトリのテストはフレームワークのテストであり、実際にはアプリケーションロジックではありません。

実際のデータベースを使用することで、フレームワークを実際に構成して使用していることをテストできます。さらに、実際のデータベースでテストしたときにのみ明らかになるフレームワークの欠点があるかもしれません(不自然な例:Spring DataはPostgreSQLのバージョン9.2をサポートしていません)。

模擬ソースに対するテストカバレッジのほとんどを記述しますが、実際にデータベースを使用して一般的に実行されるユースケースのエンドツーエンドテストをいくつか記述します。


単体テストの場合は、フレームワークを使用するレイヤーとは別にフレームワークをテストします。すべての単体テストが完了した後は、常にいくつかの統合テストがあるはずです。
Denise Skidmore

2

ほとんどの場合、インメモリデータベーステストはモックよりも単純です。また、はるかに柔軟です。また、移行ファイルが適切に実行されていることもテストします(移行ファイルがある場合)。

この疑似コードを参照してください:

class InMemoryTest 
{
    /** @test */
    public function user_repository_can_create_a_user()
    {
        $this->flushDatabase();

        $userRepository = new UserRepository(new Database());
        $userRepository->create('name', 'email@email.com');

        $this->seeInDatabase('users', ['name' => 'name', 'email' => 'email@email.com']);
    }
}

class MockingDBTest
{
    /** @test */
    public function user_repository_can_create_a_user()
    {
        $databaseMock = MockLib::mock(Database::class);
        $databaseMock->shouldReceive('save')
                     ->once()
                     ->withArgs(['users', ['name' => 'name', 'email' => 'email@email.com']]);

        $userRepository = new UserRepository($databaseMock);
        $userRepository->create('name', 'email@email.com');
    }
}

は、InMemoryTest動作するようDatabaseに実装される方法に依存しませんUserRepository。単にUserRepositoryパブリックインターフェイス(create)を使用し、それに対してアサートします。実装を変更してもテストは中断しませんが、速度は遅くなります。

一方、は、への実装MockingDBTest方法に完全に依存DatabaseしていUserRepositoryます。実際、実装を変更しても別の方法で機能させると、そのテストは失敗します。

両方の長所は、インターフェイスを実装する偽物を使用することDatabaseです。

class UsingAFakeDatabaseTest
{
    /** @test */
    public function user_repository_can_create_a_user()
    {
        $fakeDatabase = new FakeDatabase();
        $userRepository = new UserRepository($fakeDatabase);
        $userRepository->create('name', 'email@email.com');

        $this->assertEquals('name', $fakeDatabase->datas['users']['name']);
        $this->assertEquals('email@email.com', $fakeDatabase->datas['users']['email']);
    }
}

interface DatabaseInterface
{
    public function save(string $table, array $datas);
}

class FakeDatabase implements DatabaseInterface
{
    public $datas;

    public function save(string $table, array $datas)
    {
        $this->datas[$table][] = $datas;
    }
}

それはより表現力があり、読みやすく、理解しやすく、コードの上位層で行われる実際のデータベースの実装に依存しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.