Readable Java system tests with good old JUnit

This article is the third in a series about system testing:

  1. Dockerized testing vs end-to-end testing
  2. How to setup Dockerized testing
  3. Readable Java system tests with good old JUnit

JUnit is poorly named. Given the name, people tend to think that it should only be used to write Java unit tests. And then people feel a bit hesitant about writing their integration tests with JUnit too. When they start with system tests, they often think they need another driver for their tests. Sure, maybe using another abstraction layer and a custom domain specific language (BDD), you can make the tests more readable for a non-programmer. That often comes at the cost of making the tests less readable for the programmers. And if we are honest, who’s going to read the tests the most? Perhaps just naming test classes and methods well and writing readable code can suffice?

The point I am trying to make is that sometimes, you can just do the simplest thing and write your system tests using plain Java and JUnit. Fewer languages, libraries and frameworks can reduce the mental load of everyone in the team.

I’ve created a java system test example project which demonstrates how you can:

  • Write system tests using Java, RestAssured and JUnit. Everyone who codes in Java knows JUnit and RestAssured gives you a nice given/when/then structure. Of course, when you are testing something other than a REST service, another test tool might be needed.
  • Group the tests into suites. Maybe you need different test suites for different environments. Maybe you even want to run some non-intrusive tests on production after each deployment? (But “Testing in Production” sounds like a topic for another blog post.)
  • Package the test classes in a single fat jar file, so it can be published to a repository and downloaded and run when needed. Maybe you want to run the tests in a pipeline, and you don’t check out your repository multiple times in your pipeline, do you? 😉 If you disagree, google “build once, deploy many” and see if that changes your mind.
  • Run the system test jar with JUnitCore runner, so you don’t need to write a custom Main class or anything silly like that.

The code can be found at: https://github.com/betrcode/java-system-test-example

Let’s try it!

Clone the repository: https://github.com/betrcode/java-system-test-example

We need to have something to run the tests against. Start a dockerized test environment by running:

docker-compose -f docker-compose/docker-compose.yml up -d

It will download all docker images and start your entire system, ready to be tested. In my previous post I wrote about how to setup dockerized testing.

$ docker-compose -f docker-compose/docker-compose.yml up -d
Creating network "dockercompose_default" with the default driver
Creating myapp-database
Creating myapp-rabbit
Creating external-nasty-xml-stub
Creating myapp

Run the system test against the dockerized environment: 

$ ./gradlew clean test -DconfigFile=config/dockerized-config.yml

> Task :test

se.bettercode.systemtest.suite.FirstTestSuite > se.bettercode.systemtest.ExampleTest.restEndpointIsOK PASSED

BUILD SUCCESSFUL in 4s
4 actionable tasks: 4 executed

This is how I would run the system tests when on my local developer machine. In a Continuous Delivery Pipeline, I would download a previously built jar and execute the tests by running the jar.

Let’s build a jar with the tests and execute the jar:

$ ./gradlew clean jar

BUILD SUCCESSFUL in 2s
3 actionable tasks: 3 executed

$ java -DconfigFile="config/dockerized-config.yml" -cp build/libs/system-tests-0.1.1-SNAPSHOT.jar org.junit.runner.JUnitCore se.bettercode.systemtest.suite.FirstTestSuite

JUnit version 4.12
[main] INFO se.bettercode.systemtest.testutils.TestSetup - Config loaded
.[main] INFO se.bettercode.systemtest.ExampleTest - Testing: http://localhost:8080/get
Time: 1,326
OK (1 test)

Finally, you can take your dockerized test environment down: 

$ docker-compose -f docker-compose/docker-compose.yml down

Stopping myapp ... done
Stopping myapp-database ... done
Stopping external-nasty-xml-stub ... done
Stopping myapp-rabbit ... done
Removing myapp ... done
Removing myapp-database ... done
Removing external-nasty-xml-stub ... done
Removing myapp-rabbit ... done
Removing network dockercompose_default

You can run this on your local machine, or on a CI server. You can run it on any machine that has Java and Docker. If you use branches, you can run it on every branch. Running system tests early is better than when the code has already been merged to master and deployed to some shared staging environment!

If you want to do something similar you can use this example code as a starting point and expand it. I hope this was valuable to you, please feel free to comment below.

If you are interested in dockerizing your test setup, read my previous post  “How to setup Dockerized testing”.

One response on “Readable Java system tests with good old JUnit

  1. Hi,

    The entire series was of great help, thanks.
    We are trying to do a system test of a service startup, in this case it is seeming to be a bit tricky where we want to create a docker environment which contains all the artifacts to run our code, and then the actual test is the “java -cp xyz.jar:abc.jar” command.
    And the assertion is going to be a 200 on a GET to the service entrypoint.

    Regards,
    G

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.