การตรวจสอบใน mocking

การทดสอบใน Java เบื้องต้น

Maria Milusheva

Senior Software Engineer

แรงจูงใจ: ไม่มีค่าที่ส่งกลับ

ในบทเรียนและแบบฝึกหัดที่ผ่านมา เราทดสอบโดยการ assert บนค่าที่ส่งกลับ

  • แต่จะเป็นอย่างไรถ้าไม่มีค่าที่ส่งกลับ?

  • หรือค่าที่ส่งกลับไม่ได้บอกอะไรมากนัก?

ตัวอย่าง: การบันทึกลงฐานข้อมูล

กราฟิกแสดงฐานข้อมูลที่กำลังรับการบันทึกไฟล์

การทดสอบใน Java เบื้องต้น

ตัวอย่าง: ฐานข้อมูล

ฐานข้อมูล (Database) คือที่เก็บข้อมูลดิจิทัลสำหรับจัดเก็บ จัดการ และรักษาความปลอดภัยของข้อมูล มีผู้ให้บริการฐานข้อมูลหลายราย: โลโก้ของฐานข้อมูลยอดนิยม

  • เซิร์ฟเวอร์ฐานข้อมูลมีความทนทาน ปลอดภัย เชื่อถือได้ และรองรับข้อมูลได้ไม่จำกัด

  • ฐานข้อมูลจริงมีขนาดใหญ่และซับซ้อนเกินไปสำหรับ unit test (แต่อาจใช้ใน integration test ได้)

การทดสอบใน Java เบื้องต้น

ตัวอย่าง: ข้อความ log

สมมติว่าเรากำลังประมวลผล log:

public class MessageProcessor {
    private InfoStore infoStore;  // Will store info log messages here
    private ErrorStore errorStore; // Will store error log messages here

    public void saveMessage(String message) {
        if (message.startsWith("[INFO]")) {
            infoStore.save(message);
        }
        if (message.startsWith("[ERROR]")) {
            errorStore.save(message);
        }
    }
}
การทดสอบใน Java เบื้องต้น

InfoStore และ ErrorStore

ต้องการเพียง interface พื้นฐานสำหรับการทดสอบ:

// Blueprints for InfoStore and ErrorStore
// Mocks don't need the mocked classes to be properly implemented
interface InfoStore {
    void save(String message);
}

interface ErrorStore {
    void save(String message);
}
การทดสอบใน Java เบื้องต้น

Mockito verify

จะทดสอบว่าข้อความถูกบันทึกโดยไม่ต้องสร้างฐานข้อมูลได้อย่างไร?

Assert ว่า mock ถูกเรียกใช้:

import static org.mockito.Mockito.verify;

Assert ว่า mock ไม่ถูกเรียกใช้:

import static org.mockito.Mockito.verifyNoInteractions;
การทดสอบใน Java เบื้องต้น

การตั้งค่าการทดสอบ

@Test
void process_savesToInfoStore_whenInfoMessage() {
  InfoStore infoStore = mock(InfoStore.class);
  ErrorStore errorStore = mock(ErrorStore.class);
  MessageProcessor messageProcessor = new MessageProcessor(infoStore, errorStore);

String message = "[INFO] Process started."; messageProcessor.saveMessage(message); // Will use either InfoStore or ErrorStore
// Verify which one of the two databases was used verify(infoStore).save(message); verifyNoInteractions(errorStore); }
การทดสอบใน Java เบื้องต้น

ข้อความแจ้ง test failure

ถ้าเราเปลี่ยนข้อความเป็น:

String message = "[ERROR] Process failed!"

จะเห็น test failure แบบนี้:

Wanted but not invoked:
infoStore.save("[ERROR] Process failed!");
Actually, there were zero interactions with this mock.
การทดสอบใน Java เบื้องต้น

เทคนิคการตรวจสอบเพิ่มเติม

ตรวจสอบได้ว่า log ถูกเรียกกี่ครั้ง:

import static org.mockito.Mockito.times;
List<String> messages = new ArrayList<>(); // Create list and add elements
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");

messageProcessor.saveMessageList(messages); // Save the three messages


verify(infoStore, times(3)).save("[INFO] Processing data...");
การทดสอบใน Java เบื้องต้น

มาฝึกกันเถอะ!

การทดสอบใน Java เบื้องต้น

Preparing Video For Download...