我一直在閱讀編寫可測試的代碼,現在正試圖通過重構我的日誌框架API來實現這一點。我主要關心的是它應該是:1)易於從業務代碼中調用,2)易於嘲弄,這樣就可以測試業務代碼,而無需調用實際日誌記錄,並且可以斷言事物已記錄或不記錄說測試。用Java編寫可模擬日誌API,正確的方法
我已經達到了可以測試的地步,但我仍然覺得它可以改進。請多多包涵。這是我迄今爲止所擁有的。
/*
* The public API, which has a mockable internal factory responsible for creating log implementations.
*/
public final class LoggerManager {
private static LoggerFactory internalFactory;
private LoggerManager() {}
public static SecurityLogger getSecurityLogger() {
return getLoggerFactory().getSecurityLogger();
}
public static SystemErrorLogger getSystemErrorLogger() {
return getLoggerFactory().getSystemErrorLogger();
}
private static LoggerFactory getLoggerFactory() {
if (internalFactory == null)
internalFactory = new LoggerFactoryImpl();
return internalFactory;
}
public static void setLoggerFactory(LoggerFactory aLoggerFactory) {
internalFactory = aLoggerFactory;
}
}
/*
* Factory interface with methods for getting all types of loggers.
*/
public interface LoggerFactory {
public SecurityLogger getSecurityLogger();
public SystemErrorLogger getSystemErrorLogger();
// ... 10 additional log types
}
public final class LoggerFactoryImpl implements LoggerFactory {
private final SecurityLogger securityLogger = new SecurityLoggerImpl();
private final SystemErrorLogger systemErrorLogger = new SystemErrorLoggerImpl();
public SecurityLogger getSecurityLogger() {
return securityLogger;
}
public SystemErrorLogger getSystemErrorLogger() {
return systemErrorLogger;
}
}
的API被稱爲像這樣的業務代碼:
LoggerManager.getSystemErrorLogger().log("My really serious error");
我會在單元測試中使用TestLoggerFactory然後嘲笑這一點,它創建測試記錄器,簡單地跟蹤所有記錄通話,並且進行有可能,例如做assertNoSystemErrorLogs():
LoggerManager.setLoggerFactory(new TestLoggerFactory());
現在這工作得很好,但我還是下跌,如果我失去了一些東西,它可以進行更多的測試友好。例如,通過使用靜態setLoggerFactory,我爲所有測試設置記錄器工廠,這意味着一個測試可能實際上會影響另一個測試。所以我最大的問題在於,創建這種輕鬆可嘲弄的API的標準方式是什麼?某種依賴注入?
請注意,這個問題更多的是編寫易於訪問和使用的API,這也很容易模擬。我的例子是一個日誌框架API的事實就在這一點上。
如果你在做JUnit測試,我會考慮使用像Mockito這樣的模擬框架,而不是實現你自己的mockable類。 同樣在Java EE環境中,您可以使用CDI與限定符/生產者來注入不同的記錄器,而不是使用靜態工廠。 – Dainesch
我同意第一個答案 - 雖然每個程序員都喜歡*自己創建一個日誌框架 - 但您花時間重新創建一個已經存在的輪子。而你的車輪版本將是專有的,不太複雜,而且測試要少得多。當然,它的功能會更少。 – GhostCat
@Dainesch當然,我可以在單元測試中使用Mockito.mock(LoggerFactory.class)而不是新的TestLoggerFactory(),但這並沒有真正改變API的設計,對吧? – yzfr1