flogger
flogger copied to clipboard
Add samples to show using Flogger in JUnit
As part of unit testing, it becomes important to test the Logged messages in case of exceptions or other such scenarios.
Is this the recommended way to test logging behaviour in tests?
@Test
public void read_invalidPath_logsError() {
Handler mockHandler = Mockito.mock(Handler.class);
ArgumentCaptor<LogRecord> logRecordCaptor = ArgumentCaptor.forClass(LogRecord.class);
//set mock handler with Argument Captor
Logger.getLogger(JsonMessageParser.class.getName()).addHandler(mockHandler);
JsonMessageParser.of(TEST_JSON).read("$.code2");
verify(mockHandler).publish(logRecordCaptor.capture());
assertThat(logRecordCaptor.getValue().getMessage()).contains("error reading [$.code2]");
}
If you know the backend you're using, you can just test using the backend's idiomatic approach. E.g. for JUL, just install a test log handler to capture the records and then assert on them.
I wouldn't think you'd need to do any mocking here though.
I was using that technique and It works when the loggers are not rate-limited
The LoggerBackend does not get the logData in the following case, if there are more than one failing Test-cases. The following unit-test becomes flaky, it sometimes works and fails other times.
e.g. If the call site is
private static final logger = FluentLogger.forEnclosingClass();
...
public String processedItem() {
try{
return processItem();
} catch (ProcessingException exception) {
logger.atInfo().atMostEvery(1, TimeUnit.MINUTE).withCause(exception).log("item %s was not processed");
return null;
}
}
Unit Tests as follows The assertion on logger does not work consistently.
@Test
public void processedItem_failureCase_null() {
assertThat(processedItem()).isNull();
}
@Test
public void processedItem_failureCase2_null() {
Handler mockHandler = Mockito.mock(Handler.class);
ArgumentCaptor<LogRecord> logRecordCaptor = ArgumentCaptor.forClass(LogRecord.class);
//set mock handler with Argument Captor
Logger.getLogger(JsonMessageParser.class.getName()).addHandler(mockHandler);
// Method under test
processedItem()
verify(mockHandler).publish(logRecordCaptor.capture());
assertThat(logRecordCaptor.getValue().getMessage()).contains("item %s was not processed");
}
Ahh yes, the right way to do that is using the GrpcScopedLoggingContext which sadly I don't think is open-sourced yet.
Basically if your Platform instance returns true for "shouldForceLogging" then everything will work, but the "nice" mechanism for that is using this GrpcScopedLoggingContext thing and that's not pushed yet (the code is pretty much done though, so I will see about getting it out soon).
Once that's there it's easy to make a JUnit rule which install a context for the duration of a test which forces all logging to happen.
Sorry to not have a better answer for you :(