Unit Testing Console Output Made Easy
Unit testing presents specific challenges around logging. A developer and DZone Core members discuss an open-source project he created to help.
Join the DZone community and get the full member experience.
Join For FreeIntroduction
Testing the console output, why even bother? Some developers don't care and some do care. I think any test which asserts some output based on the same action for your target class is useful as it validates the behavior of your service when it is called. Your target class or some other class under the covers may generate logs or any kind of output on the console which you want to capture to assert it. Testing these kinds of cases will give you more confidence that your application is working as expected.
Capturing the console output and using that to assert isn't that hard in plain java. It is actually very easy but verbose. Most of the time I ended up creating a utility class which I copied to different projects. I had to maintain different versions which was not so fun at all. So I decided to generate a library out of it and contribute back to the community to give them also the possibility of capturing the console output without introducing verbose code.
Install the Library
Include the following dependency in your project as a test dependency:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>consolecaptor</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
Or get here the latest version: Maven Central
View the source code here: GitHub - ConsoleCaptor
Target Service Class
Let's assume you have the following service which creates output on the console:
public class FooService {
public void sayHello() {
System.out.println("Keyboard not responding. Press any key to continue...");
System.err.println("Congratulations, you are pregnant!");
}
}
Unit Test
Let's create a unit test for this service to assert the generated messages on the console:
import static org.assertj.core.api.Assertions.assertThat;
import nl.altindag.console.ConsoleCaptor;
import org.junit.jupiter.api.Test;
public class FooServiceTest {
@Test
public void captureStandardAndErrorOutput() {
ConsoleCaptor consoleCaptor = new ConsoleCaptor();
FooService fooService = new FooService();
fooService.sayHello();
assertThat(consoleCaptor.getStandardOutput()).contains("Keyboard not responding. Press any key to continue...");
assertThat(consoleCaptor.getErrorOutput()).contains("Congratulations, you are pregnant!");
consoleCaptor.close();
}
}
Testing Logs From Loggers
ConsoleCaptor is able to capture anything which is printed on the console even logs from logging API such as SLF4J, Log4J2, Log4J, Java Util Logging. It will return just the raw text including the log level, timestamp, etc. If you require to do more advanced logging assertions I can recommend LogCaptor, which is also capable of capturing an exception that is being logged by the logging API or the MDC (managed diagnostic context) information. Please have a look here: LogCaptor - Unit Testing Log Messages Made Easy.
Published at DZone with permission of Hakan Altındağ. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments