การทดสอบ - ฐานข้อมูลในหน่วยความจำเทียบกับการเยาะเย้ย


12

เมื่อเขียนการทดสอบทำไมบางคนต้องการใช้ฐานข้อมูลในหน่วยความจำมากกว่าเพียงการล้อเลียนข้อมูล

ฉันเห็นว่าฐานข้อมูลในหน่วยความจำอาจมีประโยชน์สำหรับการทดสอบคลังเก็บของ แต่ถ้าใช้เฟรมเวิร์ก (เช่น Spring Data) การทดสอบที่เก็บจะเป็นการทดสอบเฟรมเวิร์กไม่ใช่ตรรกะแอปพลิเคชัน

อย่างไรก็ตามการเยาะเย้ยดูเหมือนจะเร็วและเป็นไปตามรูปแบบเดียวกันกับที่ใช้โดยทั่วไปเมื่อเขียนการทดสอบหน่วยและ TDD

แล้วฉันจะพลาดอะไรไป? ฐานข้อมูลในหน่วยความจำจะมีประโยชน์เมื่อใด / ทำไม?

คำตอบ:


14

การเยาะเย้ยเป็นวิธีแก้ปัญหาที่เหมาะสำหรับการทดสอบหน่วยและอาจใช้สำหรับการทดสอบแบบรวมเพื่อปรับปรุงความเร็ว แต่มันก็ไม่ได้ให้ความมั่นใจในระดับเดียวกับเมื่อคุณใช้ฐานข้อมูลในหน่วยความจำ คุณควรเขียนการทดสอบแบบครบวงจรที่คุณกำหนดค่าแอปพลิเคชันทั้งหมดให้ใกล้เคียงที่สุดกับวิธีการกำหนดค่าการผลิตและดำเนินการทดสอบอัตโนมัติกับมัน การทดสอบเหล่านี้ควรใช้ฐานข้อมูลจริง - ในหน่วยความจำนักเทียบท่า VM หรือการปรับใช้อื่น ๆ

แต่ถ้าใช้เฟรมเวิร์ก (เช่น Spring Data) การทดสอบที่เก็บจะเป็นการทดสอบเฟรมเวิร์กไม่ใช่ตรรกะแอปพลิเคชัน

โดยการใช้ฐานข้อมูลจริงคุณกำลังทดสอบว่าคุณกำหนดค่าจริงและใช้งานเฟรมเวิร์กอย่างถูกต้อง นอกจากนี้อาจมีข้อบกพร่องในเฟรมเวิร์กที่เปิดเผยเมื่อทดสอบกับฐานข้อมูลจริงเท่านั้น (ตัวอย่างที่วางแผนไว้: Spring Data ไม่รองรับ PostgreSQL รุ่น 9.2)

ฉันจะเขียนรายงานการทดสอบส่วนใหญ่ของฉันกับแหล่งที่มาที่เยาะเย้ย แต่ฉันจะเขียนการทดสอบแบบ end-to-end สำหรับกรณีการใช้งานทั่วไปโดยใช้ฐานข้อมูลจริง


ถ้าเป็นการทดสอบหน่วยคุณจะทดสอบเฟรมเวิร์กแยกจากเลเยอร์ที่ใช้เฟรมเวิร์ก ควรมีการทดสอบการรวมหลังจากทำการทดสอบหน่วยทั้งหมดแล้ว
เดนิส 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.