I want to test a method whether it's creating correct logs or not. My class looks like this:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
class EventLogHandler {
private final Logger logger = LoggerFactory.getLogger(EventLogHandler.class);
private final Marker eventMarker = MarkerFactory.getMarker("EVENT");
public void handle(final Event event) {
final String log = SomeOtherClass.createLog(event);
logger.info(eventMarker, log);
}
}
I've seen some examples/solutions for testing logs but all of them are using Log4j, which we are not using in the project. I can only use Log4j2 of spring-boot, Slf4j and Logback classic. How can I test that handle(...) method with my existing dependencies?
With the current implementation you cannot test/verify the invocations on logger
without engaging a logging system and asserting on its output e.g. introduce logback and configure it with a stdout appender and capture stdout and assert against it etc.
In order to test your class without doing any of that you have to get your hands on the logger
instance in use in EventLogHandler
. The current implementation makes this difficult by constructing the logger
like this:
private final Logger logger = LoggerFactory.getLogger(EventLogHandler.class);
A common approach to testing in this scenario is to refactor the creation of logger in such a way that you can inject a mocked instance into EventLogHandler
when running your tests. For example:
class EventLogHandler {
private final Marker eventMarker = MarkerFactory.getMarker("EVENT");
private final Logger logger;
public EventLogHandler() {
this(LoggerFactory.getLogger(EventLogHandler.class));
}
// probably only used by your test case
public EventLogHandler(Logger logger) {
this.logger = logger;
}
public void handle(final Event event) {
logger.info(eventMarker, log);
}
}
Then test it like so:
@Test
public void someTest() {
Logger logger = Mockito.mock(Logger.class);
EventLogHandler sut = new EventLogHandler(logger);
sut.handle(event);
// verify that the right state is extracted from the given event and that the correct marker is used
Mockito.verify(logger).info(..., ...);
}
A less common alternative would be to use Powermock to allow you to mock this call: LoggerFactory.getLogger(EventLogHandler.class);
and then use Mockito to verify calls onto it in the same way as is shown above..