I've been reading up on writing testable code and am now trying to put that into practise by refactoring my logging framework API. My main concern is that it should be 1) easy to call from business code, and 2) easily mockable, so that business code can be tested without invoking the real logging and also making it possible to assert that things have been logged or not from said tests.
I've reached a point where it feels pretty testable, but I still feel it can be improved. Please bear with me. This is what I have so far.
/*
* 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;
}
}
The API is called like this in business code:
LoggerManager.getSystemErrorLogger().log("My really serious error");
I would then mock this in unit tests using a TestLoggerFactory, which creates test loggers that simply keeps track of all logging calls and makes it possible to for example do assertNoSystemErrorLogs():
LoggerManager.setLoggerFactory(new TestLoggerFactory());
Now this works fine, but I still fell as if I'm missing something and it can be made more test friendly. For example, by using the static setLoggerFactory I'm setting the logger factory for all tests, which means one test can actually affect another. So my big question here is, what is the standard way of creating this kind of easily mockable API? Some kind of Dependency Injection?
Aucun commentaire:
Enregistrer un commentaire