How to Create Dependency Injections in JUnit

The purpose of a unit test is to identify the bugs in an application as quickly as possible. Although multiple channels can lead you to the same destination, you should try to choose the most efficient way.


A JUnit test suite can have multiple test classes that require the same data, but you cannot reuse test data. In previous versions of JUnit, a good approach was to create a helper method and then call that method each time a test class needed its data.

JUnit 5 offers a more efficient approach to this problem: Dependency Injection (DI).


What is Dependency Injection?

DI is a design pattern where one object provides the dependencies of another object. When you create a Java application, you might have a class that depends on an object that creates another class to perform its function.

To use an object from another class, you would need to create a new instance of that object within its dependent class before dependency injection. So if you had multiple classes that depended on the same object, you would need to create multiple instances of it within the dependent classes.

DI allows you to use an object in a dependent class without creating a new instance of it in that class.

Dependency injection in JUnit 5

JUnit 5 allows you to inject dependencies into both test methods and constructors. This is important because the previous versions of the framework did not allow test methods or constructors with parameters.

With JUnit 5 you can insert as many parameters as you like. The only catch is that the ParameterResolver API needs to be able to resolve each parameter at runtime. JUnit currently has three built-in parameter resolvers that are used automatically. To use a different resolver, you would have to register it explicitly by using the @ExtendWith annotation.

Inject dependencies into JUnit

This sample program uses one of JUnit’s built-in parameters (the TestInfoParameterResolver) to demonstrate how you can inject a dependency into a JUnit 5 test. The TestInfoParameterResolver resolves objects belonging to the TestInfo interface. So JUnit 5 supplies an instance of the TestInfo interface to each method or constructor that uses it.

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

class InfoTestInterfaceTest {
InfoTestInterfaceTest(TestInfo testInfo) {
assertEquals("InfoTestInterfaceTest", testInfo.getDisplayName());
}


@Test
void testMethodName(TestInfo testInfo) {
assertEquals("testMethodName(TestInfo)", testInfo.getDisplayName());
}

@Test
@DisplayName("method using the @DisplayName annotation")
void testMethodNameTwo(TestInfo testInfo) {
assertEquals("method using the @DisplayName annotation", testInfo.getDisplayName());
}
}

The JUnit test above shows how to inject an object into a constructor and two methods. The JUnit TestInfo interface has four methods that you can use with its object.

The getDisplayName() method is the most useful. It returns the friendly name of the current test method or constructor. By default, this name is based on the class. However, if you use the @DisplayName annotation, the getDisplayName() method returns this text instead.

The above test class generates the following test report:

Use DI in @Before and @After methods

There are four other types of annotated JUnit methods that support dependencies. These are the @BeforeAll, @BeforeEach, @AfterAll, and @AfterEach annotations. As with the @Test method, all you need to do is pass an object as a parameter to either the before or after method and you’re good to go.

The @Before and @After annotations are important because they also help you develop more efficient test code. The ability to also inject dependencies into these methods further improves your test code.

Leave a Reply

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