태그 보관물: tdd

tdd

테스트-인 메모리 DB와 모의 프레임 워크를 사용하는 경우 리포지토리를

테스트를 작성할 때 누군가가 데이터를 모의하는 것보다 메모리 내 데이터베이스를 사용하려는 이유는 무엇입니까?

인 메모리 데이터베이스가 리포지토리를 테스트하는 데 도움이 될 수 있음을 알 수있었습니다. 그러나 스프링 데이터와 같은 프레임 워크를 사용하는 경우 리포지토리를 테스트하면 실제로 응용 프로그램 논리가 아닌 프레임 워크를 테스트하게됩니다.

그러나 조롱은 더 빠르며 단위 테스트 및 TDD를 작성할 때 일반적으로 사용되는 것과 동일한 패턴을 따릅니다.

그래서 내가 무엇을 놓치고 있습니까? 인 메모리 데이터베이스가 언제 / 왜 도움이됩니까?



답변

Mocking은 단위 테스트에 이상적인 솔루션이며 속도를 향상시키기 위해 통합 테스트에도 사용될 수 있지만 인 메모리 데이터베이스를 사용할 때와 동일한 수준의 신뢰도를 제공하지는 않습니다. 프로덕션 구성 방법에 최대한 가깝게 전체 애플리케이션을 구성하고 이에 대해 자동화 된 테스트를 실행하는 엔드 투 엔드 테스트를 작성해야합니다. 이러한 테스트는 메모리 내, 도커, VM 또는 기타 배포와 같은 실제 데이터베이스를 사용해야합니다.

그러나 스프링 데이터와 같은 프레임 워크를 사용하는 경우 리포지토리를 테스트하면 실제로 응용 프로그램 논리가 아닌 프레임 워크를 테스트하게됩니다.

실제 데이터베이스를 사용하여 실제로 프레임 워크를 올바르게 구성하고 사용하고 있는지 테스트하고 있습니다. 또한 실제 데이터베이스로 테스트 할 때만 공개되는 프레임 워크의 단점이있을 수 있습니다 (예 : Spring Data는 PostgreSQL 버전 9.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방법에 전적으로 의존합니다 . 실제로 구현을 변경했지만 여전히 다른 방식으로 작동하면 테스트가 중단됩니다.DatabaseUserRepository

두 세계의 최고 는 인터페이스를 구현 하는 가짜를 사용하는 것입니다 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;
    }
}

이는보다 표현적이고 읽기 쉽고 이해하기 쉬운 방법이며 더 높은 코드 계층에서 수행되는 실제 데이터베이스의 구현에 의존하지 않습니다.


답변