Java 測試入門
Maria Milusheva
Senior Software Engineer
在前一個課程與練習中,我們透過對回傳值斷言來測試。
但如果沒有回傳值呢?
或是回傳值不重要、資訊不足呢?
例子:儲存到資料庫。

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

資料庫伺服器具備耐久、安全、可靠與近乎無限的容量
真實資料庫過於龐大且複雜,不適合單元測試(但可用於整合測試)
假設我們在處理日誌:
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);
}
}
}
讓測試能運作,你只需要基本的介面:
// InfoStore 與 ErrorStore 的藍圖
// 模擬物件不需要被模擬的類別有完整實作
interface InfoStore {
void save(String message);
}
interface ErrorStore {
void save(String message);
}
如何在不建立任何資料庫的情況下,測試訊息已被儲存?
斷言有使用到模擬物件:
import static org.mockito.Mockito.verify;
斷言沒有使用到模擬物件:
import static org.mockito.Mockito.verifyNoInteractions;
@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); }
如果我們改成這則訊息:
String message = "[ERROR] Process failed!"
就會看到像這樣的測試失敗:
Wanted but not invoked:
infoStore.save("[ERROR] Process failed!");
Actually, there were zero interactions with this mock.
我們也能精確驗證呼叫次數:
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 測試入門