Suppressing Logs in Successful Tests
I recently got so fed up with these kinds of logs, that I wrote a small library for suppressing them. What it does is quite simple:
- It stores all existing loggers and their configured appenders.
- Before executing a test, it replaces all appenders with a RecordingAppender.
- While the tests are executed, this appender remembers all logging events.
- After the test was executed, it restores the original logger configuration.
- Only if the test failed, the collected log events are sent to their corresponding original appenders.
The library is licensed under
Apache 2.0 and available on Maven Central:
1 2 3 |
group: info.novatec.testit artifact: testutils-logsuppressor-logback version: 0.2 |
You can check out the source code on GitHub. Included in this library is a JUnit 4
Rule and a JUnit 5
Extension. Additionally it is assumed, that logging is done with Logback.
Examples
Class Under Test
1 2 3 4 5 6 7 8 9 |
public class SomeService { private static final Logger log = LoggerFactory.getLogger(SomeService.class); void doSomething() { log.error("foo"); } } |
In JUnit 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@ExtendWith(LogbackSuppressorExtension.class) class LogbackSuppressorExtensionDemo { SomeService cut = new SomeService(); @Test void thisWillHaveNoLog() { cut.doSomething(); } @Test void thisWillHaveLogBecauseOfFailure() { cut.doSomething(); Assertions.fail("foo bar"); } @Test void thisWillHaveLogBecauseOfException() { cut.doSomething(); throw new IllegalStateException(); } } |
In JUnit 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class LogbackSuppressorRuleDemo { @Rule public LogbackSuppressorRule logSuppressor = new LogbackSuppressorRule(); SomeService cut = new SomeService(); @Test public void thisWillHaveNoLog() { cut.doSomething(); } @Test public void thisWillHaveLogBecauseOfFailure() { cut.doSomething(); Assert.fail("foo bar"); } @Test public void thisWillHaveLogBecauseOfException() { cut.doSomething(); throw new IllegalStateException(); } } |
Comment article
Recent posts

May 2022
Alexander Miller & Sebastian Letzel
Kotlin Assertion Libraries - Conclusions

May 2022
Sebastian Letzel & Alexander Miller
Kotlin Assertion Libraries - Kluent

April 2022
Stefan Ludwig
Asserting Log-Messages with LogRecorder

December 2021
Alexander Miller & Sebastian Letzel
Kotlin Assertion Libraries - Atrium

November 2021
Tioman Gally
JUnit5 Custom Extension: ParameterResolver with Kotlin

July 2021
Sebastian Letzel & Alexander Miller
Kotlin Assertion Libraries - Strikt
Comments
Rusty Phillips
This is a pretty good idea!
Choosing to implement this as a rule is perhaps not as good a choice as you could have since you’d probably want it to be defined on every single test, and that means having to add a rule to every single class, or having every single class inherit from a single class – both of which seem like bad ideas.
Have you considered setting it up as a runlistener instead?
Then you need only add it to your surefire/failsafe config (both of which can take runlisteners as arguments) and it’ll run for each test.
Stefan Ludwig
Thanks!
Yeah, if used at scale, it should probably be implemented on a more global level. Either as a lifecycle listener, like you mentioned, for Maven or Gradle, or as a globally registered extension for JUnit 5. I would prefer a JUnit 5 based solution because it would apply the suppression even if tests are executed outside a regular build (e.g. explicitly in your IDE).