Kiểm tra - DB trong bộ nhớ so với Mocking


11

Khi viết bài kiểm tra, tại sao ai đó muốn sử dụng cơ sở dữ liệu trong bộ nhớ thay vì chỉ chế nhạo dữ liệu?

Tôi có thể thấy rằng cơ sở dữ liệu trong bộ nhớ có thể có lợi cho việc kiểm tra kho lưu trữ của một người. Nhưng nếu sử dụng một khung công tác (như Spring Data), việc kiểm tra các kho lưu trữ sẽ là kiểm tra khung và không thực sự là logic ứng dụng.

Mocking, tuy nhiên, có vẻ nhanh hơn và theo cùng một mô hình thường được sử dụng khi viết bài kiểm tra đơn vị và TDD.

Vậy tôi còn thiếu gì? Khi nào / tại sao một cơ sở dữ liệu trong bộ nhớ sẽ có lợi?

Câu trả lời:


14

Mocking là giải pháp lý tưởng cho các bài kiểm tra đơn vị và nó cũng có thể được sử dụng cho các bài kiểm tra tích hợp để cải thiện tốc độ, nhưng nó không cung cấp mức độ tin cậy như khi bạn sử dụng cơ sở dữ liệu trong bộ nhớ. Bạn nên viết các bài kiểm tra đầu cuối trong đó bạn định cấu hình toàn bộ ứng dụng càng gần càng tốt với cách nó được cấu hình sản xuất và chạy thử nghiệm tự động đối với nó. Các thử nghiệm này nên sử dụng cơ sở dữ liệu thực - trong bộ nhớ, docker, VM hoặc một số triển khai khác.

Nhưng nếu sử dụng một khung công tác (như Spring Data), việc kiểm tra các kho lưu trữ sẽ là kiểm tra khung và không thực sự là logic ứng dụng.

Bằng cách sử dụng cơ sở dữ liệu thực tế, bạn đang kiểm tra rằng bạn thực sự định cấu hình và sử dụng khung chính xác. Hơn nữa, có thể có những thiếu sót trong khung chỉ được tiết lộ khi thử nghiệm với cơ sở dữ liệu thực tế (ví dụ giả định: Spring Data không hỗ trợ phiên bản 9.2 của PostgreQuery).

Tôi sẽ viết hầu hết phạm vi kiểm tra của mình đối với các nguồn bị chế giễu, nhưng tôi sẽ viết một số thử nghiệm từ đầu đến cuối cho các trường hợp sử dụng thường được sử dụng bằng cơ sở dữ liệu thực.


Nếu đó là kiểm tra Đơn vị, bạn sẽ kiểm tra khung riêng biệt với lớp sử dụng khung. Luôn phải có một số thử nghiệm tích hợp sau khi tất cả các thử nghiệm đơn vị được thực hiện.
Denise Skidmore

2

Hầu hết thời gian, kiểm tra cơ sở dữ liệu trong bộ nhớ đơn giản hơn so với chế độ chế nhạo. Nó cũng linh hoạt hơn rất nhiều. Và nó cũng kiểm tra các tệp di chuyển được thực hiện tốt (khi có các tệp di chuyển).

Xem mã giả này:

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');
    }
}

Việc InMemoryTestnày không phụ thuộc vào cách Databasetriển khai vào UserRepositorycông việc. Nó chỉ đơn giản là sử dụng UserRepositorygiao diện công cộng ( create) và sau đó khẳng định chống lại nó. Thử nghiệm đó sẽ không bị hỏng nếu bạn thay đổi triển khai nhưng chậm hơn.

Trong khi đó, các MockingDBTestphụ thuộc đầy đủ vào cách Databasethực hiện vào UserRepository. Trong thực tế, nếu bạn thay đổi việc thực hiện nhưng vẫn khiến nó hoạt động theo cách khác, thử nghiệm đó sẽ bị hỏng.

Tốt nhất của cả hai thế giới sẽ sử dụng giao diện giả thực hiện Databasegiao diện:

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;
    }
}

Đó là cách biểu cảm hơn, dễ đọc và dễ hiểu hơn và nó không phụ thuộc vào việc triển khai Cơ sở dữ liệu thực tế được thực hiện ở các lớp mã cao hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.