模擬中的驗證

Java 測試入門

Maria Milusheva

Senior Software Engineer

動機:沒有回傳值

在前一個課程與練習中,我們透過對回傳值斷言來測試。

  • 但如果沒有回傳值呢?

  • 或是回傳值不重要、資訊不足呢?

例子:儲存到資料庫。

有檔案被儲存進去的資料庫圖像

Java 測試入門

例子:資料庫

Database——用來儲存、管理與保護結構化資料的數位儲存庫。有許多資料庫供應商: 一些常見資料庫的標誌

  • 資料庫伺服器具備耐久、安全、可靠與近乎無限的容量

  • 真實資料庫過於龐大且複雜,不適合單元測試(但可用於整合測試)

Java 測試入門

例子:日誌訊息

假設我們在處理日誌:

public class MessageProcessor {
    private InfoStore infoStore;  // 會在這裡儲存 info 日誌
    private ErrorStore errorStore; // 會在這裡儲存 error 日誌

    public void saveMessage(String message) {
        if (message.startsWith("[INFO]")) {
            infoStore.save(message);
        }
        if (message.startsWith("[ERROR]")) {
            errorStore.save(message);
        }
    }
}
Java 測試入門

InfoStore 與 ErrorStore

讓測試能運作,你只需要基本的介面:

// InfoStore 與 ErrorStore 的藍圖
// 模擬物件不需要被模擬的類別有完整實作
interface InfoStore {
    void save(String message);
}

interface ErrorStore {
    void save(String message);
}
Java 測試入門

Mockito 的 verify

如何在不建立任何資料庫的情況下,測試訊息已被儲存?

斷言有使用到模擬物件:

import static org.mockito.Mockito.verify;

斷言沒有使用到模擬物件:

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); // 會使用 InfoStore 或 ErrorStore 其中之一
// 驗證實際使用了哪一個「資料庫」 verify(infoStore).save(message); verifyNoInteractions(errorStore); }
Java 測試入門

測試失敗訊息

如果我們改成這則訊息:

String message = "[ERROR] Process failed!"

就會看到像這樣的測試失敗:

Wanted but not invoked:
infoStore.save("[ERROR] Process failed!");
Actually, there were zero interactions with this mock.
Java 測試入門

更多驗證技巧

我們也能精確驗證呼叫次數:

import static org.mockito.Mockito.times;
List<String> messages = new ArrayList<>(); // 建立清單並加入元素
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");

messageProcessor.saveMessageList(messages); // 儲存三則訊息


verify(infoStore, times(3)).save("[INFO] Processing data...");
Java 測試入門

一起來練習吧!

Java 測試入門

Preparing Video For Download...