Monday, 12 December 2016

Test log lines

Some times the only thing we are interested in testing is weather a log line correctly gets logged. This is not the most optimal test but sometimes its required... in cases where log lines are getting monitored by a monitoring agent and we want to make sure correct format gets logged etc.

The trick is to mock the Log Appender and then capture the logs on that appender in a safe way. Once these log lines are captured you can verify them to your hearts content....

A fully working example of this is given at: https://github.com/njaiswal/logLineTester

Following snippet shows how to achieve this:

// Fully working test at: https://github.com/njaiswal/logLineTester/blob/master/src/test/java/com/nj/Utils/UtilsTest.java
@Test
public void testUtilsLog() throws InterruptedException {
Logger utilsLogger = (Logger) LoggerFactory.getLogger("com.nj.utils");
final Appender mockAppender = mock(Appender.class);
when(mockAppender.getName()).thenReturn("MOCK");
utilsLogger.addAppender(mockAppender);
final List<String> capturedLogs = Collections.synchronizedList(new ArrayList<>());
final CountDownLatch latch = new CountDownLatch(3);
//Capture logs
doAnswer((invocation) -> {
LoggingEvent loggingEvent = invocation.getArgumentAt(0, LoggingEvent.class);
capturedLogs.add(loggingEvent.getFormattedMessage());
latch.countDown();
return null;
}).when(mockAppender).doAppend(any());
//Call method which will do logging to be tested
Application.main(null);
//Wait 5 seconds for latch to be true. That means 3 log lines were logged
assertThat(latch.await(5L, TimeUnit.SECONDS), is(true));
//Now assert the captured logs
assertThat(capturedLogs, hasItem(containsString("One")));
assertThat(capturedLogs, hasItem(containsString("Two")));
assertThat(capturedLogs, hasItem(containsString("Three")));
}

Thursday, 11 February 2016

Run background server during integration tests

Most of the times during integration testing we have to run the built java code in server mode and run client junit/testng tests against the server. Mostly this has to be also done on the CI Jenkins server as well. Following post will go through some of the techniques to achieve the same.

Assuming the project is built in maven, run the integration test server (your application) in the pre-integration-test phase using maven-ant-run plugin.

<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>start-test-server</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<!-- To debug this forked process, set spawn=false only then stdout and stderr of process will be visible -->
<!-- Test will not run if spawn=false, but helps debug test server runs -->
<java spwan="true" fork="true" classname="your.example.com.MainClass">
<jvmarg value="-Dproperties.file=file:/path/to/app.properties"/>
<classpath refid="maven.test.classpath"/> <!-- This basically means we will run current build -->
<env key="LD_LIBRARY_PATH" value="${yourNativeLibs}:${env:LD_LIBRARY_PATH}"/>
</java>
</target>
</configuration>
</execution>
</executions>
</plugin>


Above maven plugin will run your main class in a forked jvm process in background and then you can run your junit/testNg integration tests against this server.

<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>


One of the issues that you will face is to stop the server once integration tests are complete.
For this you can create a method call to exit the test server if possible or exit the test server after a time interval. However this needs to be implemented server side. If you only run integration tests on Jenkins, Jenkins will make sure to kill all the pids that were created during a integration test run and keep integration test environment clean.

Happy testing...