JUnit 5 was formally released in July 2016 and is quite a major evolution to JUnit 4 which has been the standard unit testing framework since Android first appeared on the scene. There are some quite significant changes and getting things set up, and then getting the best out of JUnit 5 can require a little effort, but the results are well worth it. In this loosely-coupled series we’ll explore a few distinct aspects of JUnit 5 and look at how we can get the best out of it. In this article we’ll look at some of the new features in JUnit 5 and see how they can simplify our tests.
Before we dive in I think it is worth explaining my preferred way of constructing unit tests and see how JUnit 5 can make life easier. I like to follow a Given...When...Then
pattern in my tests. The ‘Given’ part specifies the state of the component under test before we actually do anything; The ‘When’ part specifies the action that we are performing; and the ‘Then’ part asserts that things behaved as we expected. For our calculator app a typical test might be: Given input values of 1 and 2; When we add them together; Then the result is 3. Let’s look at how we would actually implement this in a JUnit 4 test:
public class CalculatorJUnit4Test { private Calculator calculator; @Before public void setup() { calculator = new Calculator(); } @Test public void givenInputsOfOneAndTwo_whenWeAddThem_thenTheResultIsThree() { float input1 = 1; float input2 = 2; float result = calculator.calculate(input1, input2, Operator.PLUS); assertThat(result).isEqualTo(3f); } }
There are a couple of aspects of this which I really don’t like. The first is the name of the test method. It is important that the test name clearly explains what we’re testing and so my preference is it actually use given..._When..._Then...
as the template for the method name because a correct name forces us to think of precisely what we’re testing, and keeps us focused. Also, if the test fails when we run it, then the test runner will display the method name(s) of the failing test(s), so it needs to clearly identify what we’re testing. However the sheer length of the method name, and the fact that Java method names cannot contain spaces, makes it difficult to read.
The other problem becomes apparent once we build a full test suite which fully tests the Calculator class: We will have a number of cases where the ‘Given’ part is the same, and a number of cases where the ‘When’ part is the same. I won’t include the full JUnit 4 test suite here, but please take a look at the source to see how large and repetitive it becomes. While JUnit 4 supports Parameterised Tests which go some way to addressing this, they tend to result in test suites which are much more difficult to understand. One useful aspect of a good test suite is that it should actually document how the system under test is expected to work. If your tests are difficult to read and understand then this documentation is lost.
Let’s start with the method naming issue. JUnit 5 offers a @DisplayName
annotation which we can use on our tests. The text which we add to this annotation is what the test runner will display in the test report. While it is still important that the method name should correctly describe the test, we can be far more terse in our method naming while still having verbose, descriptive test names in the test report.
So let’s take our JUnit 4 test and convert it to JUnit 5 to make use of this:
public class CalculatorJUnit5Test { private Calculator calculator; @BeforeEach public void setup() { calculator = new Calculator(); } @Test @DisplayName("Given inputs of One and Two When we add them Then the result is Three") public void testOnePlusTwoEqualsThree() { float input1 = 1; float input2 = 2; float result = calculator.calculate(input1, input2, Operator.PLUS); assertThat(result).isEqualTo(3f); } }
Although this is more verbose than the JUnit 4 code, I personally find it much easier to read and understand precisely what it is that we’re testing. When we come to run this then the JUnit 5 test report is definitely much more readable than the JUnit 4 one:
So we’ve made the report a little easier to understand, and also made the method names of our tests a bit easier to read, but our tests are still pretty verbose – the full JUnit5 test suite is 149 lines, an increase on the 136 lines of the JUnit 4 test, which is still making them quite difficult to read. In the next article in this series we’ll turn our attention to the repetition of boilerplate issue and look at how JUnit 5 can help with that.
The source code for this article is available here.
© 2017, Mark Allison. All rights reserved.
Copyright © 2017 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.