Overview

Given-When-Then in JUnit Tests

2 Comments

Looking at JUnit tests can be a bit weird at times. Often a lot of preparation work in terms of preparing mock objects and responses is required. Even though this is very well supported by tools like Mockito and PowerMock, the resulting test code is not always easy to read, understand and thus maintain.

Structure your test cases

There is a simple ruse to make JUnit tests more readable right away that does not even require any additional effort. Simply divide your tests โ€“ using comments โ€“ into three sections for preparation, execution, and verification. It almost feels a bit trivial writing a blog post about this, but often enough things like this get lost in everyday project work.

The following code snippet shows an example of this approach. Of course examples are always easier than code in the real word. Anyway, I strongly believe that this division already helps a lot.

/**
  * If an item is loaded from the repository, the name of that item should 
  * be transformed into uppercase.
  */
@Test
public void shouldReturnItemNameInUpperCase() {
 
    //
    // Given
    //
    Item mockedItem = new Item("it1", "Item 1", "This is item 1", 2000, true);
    when(itemRepository.findById("it1")).thenReturn(mockedItem);
 
    //
    // When
    //
    String result = itemService.getItemNameUpperCase("it1");
 
    //
    // Then
    //
    verify(itemRepository, times(1)).findById("it1");
    assertThat(result, is("ITEM 1"));
}

The purpose of the different sections should be quite obvious. But let’s have a short overview of those nonetheless.

Preparation -> Given
Here objects are created that are required as return values for mocked method calls or as input parameters to the method under test. Furthermore, the mocked method calls as such are prepared in this section. Often this is the longest and most complicated part of a JUnit test.
Note: It might be a bit confusing that the Mockito statements starting with when are part of the Given-section. But as this is related to the preparation of the test execution, this is perfectly fine.

Execution -> When
This basically only calls the tested method. It can thus always very easily be seen what is tested with a certain JUnit test. This is usually the shortest part of a test.

Verification -> Then
In this section, assertions on any results from the execution step are implemented. In addition, it can be checked if certain (mocked) method calls have happened. At least those are the typical things to check here.

Naming of test cases (test methods)

In earlier days test methods had to be prefixed with “test”. Just do not do this anymore. Some colleagues like to use underscores in the method names of JUnit tests. Personally I prefer to follow the naming conventions also used in other parts of the codebase. Typically this is camelCase.

Of course one could try to include a lot of information to the method name, but maybe it is better to put this to the comment section of the method. Stating what should happen using method names like shouldReturnItemNameInUpperCase() might be a good compromise with respect to the amount of information about the testcase. Obviously it would be good to agree on those conventions in the project before things start to run into different directions.

A word on preparing test objects

This blog post could basically be finished here. But I would like to add a few thoughts on creating test objects in JUnit tests. This can be a nerve-wracking task, especially if there is a need for a lot of information in those objects to execute a certain test properly. Especially if the same kind of object is required for different tests it might be tempting to generalize this and share functionality between different test cases. Sometimes this for sure is the right way to go. But it also makes it harder to really have independent test cases. Having the right values in those objects to work with all affected tests can make things complicated as time goes by and more and more tests depend on the same test objects. Thus it might make sense to think twice in those cases and consider creating individual test objects for individual test cases.

Tags

Thomas Jaspers

Long-term experience in agile software projects using
Java enterprise technologies. Interested in test automation tools and concepts.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentare

Comment

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