'Coding has over 700 languages', '67% of programming jobs aren’t in the technology industry', 'Coding is behind almost everything that is powered by electricity', 'Knowing how to code is a major requirement for astronomers', 'The first computer didn’t use any electricity', 'Do you know there is a coding language named “Go“', 'Computer programming is one of the fastest-growing careers', 'Fortran (FORmula TRANslation) was the name of the first programming language', 'The first programmer was the daughter of a mad poet', 'Many programming languages share the same structure', 'Coding will soon be as important as reading', 'How many programmers does it take to change a light bulb? None, that’s a hardware problem', 'Why do Java developers wear glasses? Because they can’t C', 'Software and temples are much the same — first we build them, then we pray', 'An engineer will not call it a bug — it’s an undocumented feature', 'In a room full of top software designers, if two agree on the same thing, that’s a majority', 'C programmers never die. They are just cast into void', 'Knock, knock … Who’s there? … *very long pause* … Java', 'The best thing about a boolean is even if you are wrong, you are only off by a bit', 'Linux is only free if your time has no value', 'The computer was born to solve problems that did not exist before', 'Coding has over 700 languages', '67% of programming jobs aren’t in the technology industry', 'Coding is behind almost everything that is powered by electricity', 'Knowing how to code is a major requirement for astronomers', 'The first computer didn’t use any electricity', 'Do you know there is a coding language named “Go“', 'Computer programming is one of the fastest-growing careers', 'Fortran (FORmula TRANslation) was the name of the first programming language', 'The first programmer was the daughter of a mad poet', 'Many programming languages share the same structure', 'Coding will soon be as important as reading', 'How many programmers does it take to change a light bulb? None, that’s a hardware problem', 'Why do Java developers wear glasses? Because they can’t C', 'Software and temples are much the same — first we build them, then we pray', 'An engineer will not call it a bug — it’s an undocumented feature', 'In a room full of top software designers, if two agree on the same thing, that’s a majority', 'C programmers never die. They are just cast into void', 'Knock, knock … Who’s there? … *very long pause* … Java', 'The best thing about a boolean is even if you are wrong, you are only off by a bit', 'Linux is only free if your time has no value', 'The computer was born to solve problems that did not exist before',
Update appNew update is available. Click here to update.
Last Updated: Jun 30, 2023

JUnit5 Dependency Injection for constructors and Methods

Author Toohina Barua
0 upvote
gp-icon
Basics of javascript
Free guided path
10 chapters
68+ problems
gp-badge
Earn badges and level up

Introduction

Test constructors or methods were not permitted to contain arguments in any previous JUnit version (at least not with the standard Runner implementations). Both test constructors and methods can now contain parameters, which is one of the primary improvements in JUnit Jupiter. This gives you more freedom and allows you to use Dependency Injection with constructors and methods.

ParameterResolver

ParameterResolver is an API for test extensions that resolve arguments dynamically during runtime. If a test class constructor, a test method, or a lifecycle method accepts a parameter, the parameter must be resolved at runtime by a registered ParameterResolver.
There are three built-in resolvers that are automatically registered at the moment:

  • TestInfoParameterResolver
  • RepetitionInfoParameterResolver
  • TestReporterParameterResolver

TestInfoParameterResolver

The TestInfoParameterResolver will give an instance of TestInfo corresponding to the current container or test as the value for the parameter if a constructor or method parameter is of type TestInfo. The TestInfo may then be used to get information about the current container or test, including the display name, test class, test method, and related tags. A technical name, such as the name of the test class or test method, or a custom name set using @DisplayName, is used as the display name.
TestInfo is a drop-in replacement for the JUnit 4 TestName rule. TestInfo may be injected into a test constructor, @BeforeEach method, and @Test method as seen below.


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

@DisplayName("TestInfo Demo")
class TestInfoDemo {

    TestInfoDemo(TestInfo testInfo) {
        assertEquals("TestInfo Demo", testInfo.getDisplayName());
    }

    @BeforeEach
    void init(TestInfo testInfo) {
        String displayName = testInfo.getDisplayName();
        assertTrue(displayName.equals("TEST 1") || displayName.equals("test2()"));
    }

    @Test
    @DisplayName("TEST 1")
    @Tag("my-tag")
    void test1(TestInfo testInfo) {
        assertEquals("TEST 1", testInfo.getDisplayName());
        assertTrue(testInfo.getTags().contains("my-tag"));
    }

    @Test
    void test2() {
    }

RepetitionInfoParameterResolver

The RepetitionInfoParameterResolver will supply an instance of RepetitionInfo if a method parameter in a @RepeatedTest, @BeforeEach, or @AfterEach method is of type RepetitionInfo. The information about the current repetition and the overall number of repetitions for the relevant @RepeatedTest can then be retrieved using RepetitionInfo. Outside of the context of a @RepeatedTest, however, RepetitionInfoParameterResolver is not registered.

TestReporterParameterResolver

The TestReporterParameterResolver will provide an instance of TestReporter if a constructor or method parameter is of type TestReporter. Additional statistics about the current test run can be published using the TestReporter. The data may be examined in IDEs or included in reports thanks to the reportingEntryPublished() function in a TestExecutionListener.
Where you used to print information to stdout or stderr in JUnit 4, you should use TestReporter in JUnit Jupiter. All reported items will be written to stdout if @RunWith(JUnitPlatform.class) is used. In addition, some IDEs publish report items to stdout or display them as test results in the user interface.

class TestReporterDemo {

    @Test
    void reportSingleValue(TestReporter testReporter) {
        testReporter.publishEntry("a status message");
    }

    @Test
    void reportKeyValuePair(TestReporter testReporter) {
        testReporter.publishEntry("a key", "a value");
    }

    @Test
    void reportMultipleKeyValuePairs(TestReporter testReporter) {
        Map<String, String> values = new HashMap<>();
        values.put("user name", "dk38");
        values.put("award year", "1974");

        testReporter.publishEntry(values);
    }

}
Get the tech career you deserve, faster!
Connect with our expert counsellors to understand how to hack your way to success
User rating 4.7/5
1:1 doubt support
95% placement record
Akash Pal
Senior Software Engineer
326% Hike After Job Bootcamp
Himanshu Gusain
Programmer Analyst
32 LPA After Job Bootcamp
After Job
Bootcamp

Example of Custom ParameterResolver

RandomParametersExtension, an example of a custom parameterResolver, is shown below. While not designed for production, it highlights the extension model's and parameter resolution process's simplicity and expressiveness. MyRandomParametersTest shows how to inject random values in @Test methods.

@ExtendWith(RandomParametersExtension.class)
class MyRandomParametersTest {

    @Test
    void injectsInteger(@Random int i, @Random int j) {
        assertNotEquals(i, j);
    }

    @Test
    void injectsDouble(@Random double d) {
        assertEquals(0.0, d, 1.0);
    }

}

Repeated tests

By annotating a method with @RepeatedTest and giving the total number of repetitions requested, JUnit 5 allows you to repeat a test a given number of times. This is especially handy when certain conditions change from one test execution to the next. Each invocation of a repeated test is treated as if it were a standard @Test method, complete with lifecycle callbacks and extensions.
The name element of the @RepeatedTest annotation may be used to give a custom display name for each repetition in addition to the number of repeats. Currently, the following placeholders are supported:

– displayName: the method's display name 

– currentRepetition: the current repetition number 

– totalRepetitions: the total number of repetitions

The following code demonstrates how to use repeated tests, display name placeholders, and the RepetitionInfo arguments. The scenario of the first repeated test ensures that the execution of the Calculator class's add function is consistent and produces the same result every time. The second repeating test case ensures that collections behave correctly: a list receives a new member with each iteration, but a set will not receive duplicate items, even if we try to insert it several times.

public class RepeatedTestsTest {

    private static Set<Integer> integerSet = new HashSet<>();
    private static List<Integer> integerList = new ArrayList<>();

    @RepeatedTest(value = 5, name =                                           //(1)
    "{displayName} - repetition {currentRepetition} of {totalRepetitions}")                 //(1)
    @DisplayName("Test add operation")
    void addNumber() {
        Calculator calculator = new Calculator();
        assertEquals(2, calculator.add(1, 1),
        "1 + 1 should equal 2");
    }
    @RepeatedTest(value = 5, name = "the list contains //(2)
    {currentRepetition} elements(s), the set contains 1 element") //(2)
    void testAddingToCollections(TestReporter testReporter,
    RepetitionInfo repetitionInfo) {
        integerSet.add(1);
        integerList.add(repetitionInfo.getCurrentRepetition());
        testReporter.publishEntry("Repetition number", //(3)
        String.valueOf(repetitionInfo.getCurrentRepetition())); //(3)
        assertEquals(1, integerSet.size());
        assertEquals(repetitionInfo.getCurrentRepetition(),
        integerList.size());
    }
}

We make the following observations in light of the preceding example:

  • The initial test is repeated five times, with the display name, current repetition number, and a total number of repetitions displayed at each repetition (1).
  • The second test is repeated five times, with the number of elements in the list (which is the current repetition number) and the fact that the set always includes just one element displayed at each repetition (2).
  • The repetition number is displayed throughout the execution of each of the repeated second tests, as it is inserted into the RepetitionInfo parameter (3).

The result of the execution of the previous tests is shown in the images below:

The names of the repeated tests at the time of the execution

 The messages are shown into the console by the second repeated test

Parameterized tests

Parameterized tests allow you to execute a test with different arguments numerous times. The main advantage is that you can create just one test and have it run on a variety of different arguments. Your tests will be safer, and you'll be able to verify a variety of input data. @ParameterizedTest is used to annotate the methods. At least one source must be declared, which gives the parameters for each invocation and subsequently consumes them in the test function.
The simplest of the potential sources is @ValueSource. To provide a single argument per parameterized test invocation, you must supply a single array of literal values. The code below demonstrates how to use this annotation. The test scenario aims to determine the number of words in a set of supplied phrases, which are provided as parameters.

class ParameterizedWithValueSourceTest {
    private WordCounter wordCounter = new WordCounter();

    @ParameterizedTest //(1)
    @ValueSource(strings = {"Check three parameters", //(2)
    "JUnit in Action"}) //(2)
   
    void testWordsInSentence(String sentence) {
        assertEquals(3, wordCounter.countWords(sentence));
    }
}

We see in the preceding example:

  • Using the appropriate annotation, we designate the test as parameterized (1).
  • The values to be supplied as parameters to the testing method are then specified (2). The testing function is called twice, once for each of the arguments supplied by the @ValueSource annotation and once for each of the arguments provided by the @ValueSource annotation.

FAQs

  1. What should we do if the type of parameter to inject is the only condition for your ParameterResolver?
    You can use the generic TypeBasedParameterResolver base class when the type of the parameter to inject is the only criteria for your parameterResolver. The supportsParameters function is used to support parameterized types and is implemented behind the scenes.
     
  2. How are some parameter resolvers explicitly enabled?
    Some parameter resolvers must be explicitly enabled by registering appropriate extensions via @ExtendWith.
     
  3. What is @test (test annotation) in JUnit?
    JUnit recognizes that the public void method to which the Test annotation is connected can be used as a test case. JUnit creates a new instance of the class before invoking the annotated method to run the method. JUnit will indicate any exceptions thrown by the test as a failure.
     
  4. What is @ValueSource in JUnit?
    @ValueSource is an ArgumentsSource which provides access to an array of literal values.
     
  5. How can we pass empty or null values into the test?
    We can pass empty or null values into the test via @EmptySource, @NullSource or @NullAndEmptySource

 

Read Also -  Difference between argument and parameter

Key Takeaways

From this article, we learn dependency Injection for constructors and Methods in Junit5 using ParameterResolver. 
But this is not enough; you need something extra to excel in web development truly. If you want to learn more about web development, you can read our articles or take our highly curated Web Development course.

Previous article
Conditional tests
Next article
JUnit Platform Launcher API
Guided path
Free
gridgp-icon
Basics of javascript
10 chapters
68+ Problems
gp-badge
Earn badges and level up
Live masterclass