Logo

dev-resources.site

for different kinds of informations.

Test utilities, or set-up methods considered harmful

Published at
11/14/2023
Categories
unittest
tdd
java
junit
Author
adambrandizzi
Categories
4 categories in total
unittest
open
tdd
open
java
open
junit
open
Author
13 person written this
adambrandizzi
open
Test utilities, or set-up methods considered harmful

One of the most interesting learnings I had in the old SEA Tecnologia is the creation of test utilities .

Test utilities are a way to reuse code in unit tests. Usually, this is done using setUpor @Before methods, but this has some disadvantages. For example, in a test case, we can have the following initialization:

private Address address;
private AddressDAO addressDAO;

@Before
public void setUp() {
    address = new Address();
    address.setStreet("Rua fulano");
    address.setNumber("123/A");
    addressDAO = new AddressDAO();
}
Enter fullscreen mode Exit fullscreen mode

This initialization works well in the test below...

@Test
public void testGetAllAddresses(){
    addressDAO.addAddress(address);

    List<Address> addresses = addressDAO.getAllAddresses();

    assertEquals(1, addresses.size());
    assertEquals("Rua fulano", addresses.get(0).getStreet());
    assertEquals("123/A", addresses.get(0).getNumber());
}
Enter fullscreen mode Exit fullscreen mode

However, in the following test, the created object is a waste, is not used at all:

@Test
public void testGetNoAddress() {
    List<Address> addresses = addressDAO.getAllAddresses();

    assertEquals(0, addresses.size());
}
Enter fullscreen mode Exit fullscreen mode

In the next following test, we have code redundancy. We also have to decide whether the other object should be created in the @Before method or in the test method:

@Test
public void testGetAllAddressesMoreThanOne() {
    addressDAO.addAddress(address);
    Address address2 = new Address();
    address2.setStreet("Outra rua");
    address2.setNumber("111");
    addressDAO.addAddress(address2);
    List<Address> addresses = addressDAO.getAllAddresses();
    assertEquals(1, addresses.size());
    assertEquals("Rua fulano", addresses.get(0).getStreet());
    assertEquals("123/A", addresses.get(0).getNumber());
}
Enter fullscreen mode Exit fullscreen mode

These inconveniences are minor when compared to the task of creating a network of dependencies. For example, to test a class Person that adds a test case Address in another test case, we will have to have one @Before similar to this:

private Person person;
private Address address;
private PersonDAO personDAO;

@Before
public void setUp() {
    address = new Address();
    address.setStreet("Rua fulano");
    address.setNumber("123/A");
    person = new Person();
    person.setName("João");
    person.setAddress(address);
    personDAO = new PersonDAO();
}
Enter fullscreen mode Exit fullscreen mode

The code for creating addresses was duplicated, and it is difficult to create the dependencies. In these examples, we see simple cases, but it is easy to see how the situation would get complicated.

We solve this problem by writing a class to create these objects. This class would be something like this:

public class TestUtil {
    public static Address utilCreateAddress(String street, String number) {
        Address address = new Address();
        address.setStreet("Rua fulano");
        address.setNumber("123/A");
        return address;
    }

    public static Person utilCreatePerson(String name, Address address) {
        Person person = new Person();
        person.setName(name);
        person.setAddress(address);
        return person;
    }
}
Enter fullscreen mode Exit fullscreen mode

Our test cases extended TestUtil, making object creation easier:

public class TestAddress2 extends TestUtil {
    private AddressDAO addressDAO = new AddressDAO();

    @Test
    public void testGetAllAddresses() {
        Address address = utilCreateAddress("Rua fulano", "123/A");
        addressDAO.addAddress(address);

        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(1, addresses.size());
        assertEquals("Rua fulano", addresses.get(0).getStreet());
        assertEquals("123/A", addresses.get(0).getNumber());
    }

    @Test
    public void testGetNoAddress() {
        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(0, addresses.size());
    }

    @Test
    public void testGetAllAddressesMoreThanOne() {
        Address address = utilCreateAddress("Rua fulano", "123/A");
        Address address2 = utilCreateAddress("Outra rua", "111");
        addressDAO.addAddress(address);
        addressDAO.addAddress(address2);

        List<Address> addresses = addressDAO.getAllAddresses();

        assertEquals(2, addresses.size());
        assertEquals("Rua fulano", addresses.get(0).getStreet());
        assertEquals("123/A", addresses.get(0).getNumber());
    }
}
Enter fullscreen mode Exit fullscreen mode

As we also frequently needed some specific object with just one or two parameters to be defined, we created methods variants:

public static Address utilCreateAddress() {
    return utilCreateAddress("Qualquer", "Qualquer");
}

public static Person utilCreatePerson() {
    return utilCreatePerson("José", utilCreateAddress());
}
Enter fullscreen mode Exit fullscreen mode

We learned that in a somewhat complex project, with large networks of object dependencies. The use of these test utilities made it possible to practice TDD on the system. It was exciting to discover that, to create that document that depended on seven other documents and five or six users, all you had to do was call a method.

Of course, there is more to our testing utilities than has been written here, and there may be even more that we haven't even done. (For example, it may be interesting to write test utilities for specific classes, instead of one gigantic utility.) However, as the idea is very simple, we hope this first step motivates you to think about the topic. Until later!

(This post was originally published as "Test Utilities, or set-up methods considered harmful" in Suspension of Disbelief. It was originally posted in an former employer's blog. As the original post went offline but the topic remains relevant, I decided to republish it.)

junit Article's
30 articles in total
Favicon
verify() method in Mockito example
Favicon
Uses of @spy annotation in junit testing
Favicon
How To Install TestNG in Eclipse: Step By Step Guide
Favicon
How to simulate real BeforeAll and AfterAll in JUnit 5
Favicon
Spring Boot Testing Best Practices
Favicon
Why there are so many assertAll methods in Junit class AssertAll? What is the use of each.
Favicon
Testando das trincheiras: Como criar mocks e stubs dinâmico com mockito em java
Favicon
Mastering Selenium Testing: JUnit Asserts With Examples
Favicon
JUnit Tutorial: An Inclusive Guide [With Enhanced Features]
Favicon
Junit Badge For Git Project
Favicon
Testes Unitários com JUnit no Java
Favicon
JUnit 5 – When to use CSV Providers
Favicon
JUnit Tutorial: An Inclusive Guide [With Enhanced Features]
Favicon
Less Code, More Tests: Exploring Parameterized Tests in JUnit
Favicon
How to find bugs before sending it to production using boundary testing technique
Favicon
Test utilities, or set-up methods considered harmful
Favicon
Dominando o Poder dos Testes Unitários em Java com JUnit: Construa Código Sólido e Confiável! 🚀🧪🔨
Favicon
How to resolve the configuration problem with 2 application.properties in Springboot?
Favicon
TestNG vs JUnit: An Unbiased Comparison Between Both Testing Frameworks
Favicon
Quick introduction to EasyRandom
Favicon
JUnit Tests in Java: A Guide to Writing Effective Unit Tests
Favicon
JUnit's @CsvSource.quoteCharacter
Favicon
Creating a REST API using Spring Boot + Tests + Documentation [part 04]
Favicon
How to use Junit and Mockito for unit testing in Java
Favicon
Unit Testing JSON Functions in Android
Favicon
Adding Unit Testing to OpenSSG
Favicon
Running JMH benchmark from Eclipse
Favicon
Setting up Junit 5 Parallel Test Execution With Maven
Favicon
Integration Tests with Micronaut and Kotlin
Favicon
Spring Boot Integration Testing with MockMvc

Featured ones: