Mock an Autowired Value Field in Spring with Junit 5

In this example I am going to show you how to mock an autowired field in Spring boot framework with Junit 5. When you use @Value annotation in Spring beans to read the value from properties file and later when you want to perform Junit test then you also need to pass value for this autowired field value otherwise you won’t be able to cover your testing. Read if you need Junit 4 version of testing for Spring’s autowired field value.

Now it is really cumbersome to place a properties file and read configuration values into those fields. Therefore Spring provides an easy way to set values to aitowired @Value fields using RefectionTestUtils‘s setField() method.

Actually you need to pass three parameters as values into setField() method. The first parameter’s value indicates the class instance for which you want to set value to the autowired field. The second parameter’s value indicates the class attribute name for which you want to set the value. The final or third parameter’s value indicates the actual value that will be set to the class attribute.

Prerequisites

Java at least 8, Gradle 6.5.1 or Maven 3.6.3, Spring Boot 2.4.0

Project Setup

You can create gradle or maven based project in your favorite IDE or tool. The name of the project is spring-mock-autowired-field-value-junit-5.

If you are using gradle as a build tool for your project then you can use below build.gradle script.

buildscript {
	ext {
		springBootVersion = '2.4.0'
	}
	
    repositories {
    	maven {
    		url 'https://plugins.gradle.org/m2/'
    	}
    }
    
    dependencies {
    	classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

plugins {
    id 'java-library'
    id 'org.springframework.boot' version "${springBootVersion}"
}

repositories {	
    jcenter()
    mavenCentral()
}

dependencies {
	implementation("org.springframework.boot:spring-boot-starter:${springBootVersion}")
	
	testImplementation "org.springframework.boot:spring-boot-starter-test:${springBootVersion}"
	
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
	testImplementation 'org.junit.platform:junit-platform-engine:1.7.0'
	testImplementation 'org.mockito:mockito-junit-jupiter:3.6.0'
}

If you are using maven as a build tool then you can use the following pom.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>spring-mock-autowired-field-value-junit-5</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.0</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<version>5.7.0</version>
		</dependency>
		
		<dependency>
			<groupId>org.junit.platform</groupId>
			<artifactId>junit-platform-engine</artifactId>
			<version>1.7.0</version>
		</dependency>
		
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-junit-jupiter</artifactId>
			<version>3.6.0</version>
		</dependency>
	</dependencies>

    <build>
        <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>at least 8</source>
					<target>at least 8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Spring Service

I am creating a simple Spring service class that has an autowired @Value annotated field that is set to a value from properties file (src/main/resources/application.properties). This @Value annotated field will be mocked in the Junit class later in this example.

package com.roytuts.spring.mock.autowired.field.value.junit;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class SpringServiceAutowiredField {

    @Value("${security.key}")
    private String securityKey;

    public void getValue() {
        System.out.println("${security.key}: " + securityKey);
    }

}

Properties File

I am creating a properties file src/main/resources/application.properties file with the following key/value pair.

security.key=SecurityKey

As I have created Spring boot application so first I will verify this autowired @Value field using main class.

Main Class

In Spring Boot application a class with main method and @SpringBootApplication annotation is enough to run the application. I am using CLI version of Spring boot application.

package com.roytuts.spring.mock.autowired.field.value.junit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringMockAutowiredValueApp implements CommandLineRunner {

    @Autowired
    private SpringServiceAutowiredField service;

    public static void main(String[] args) {
        SpringApplication.run(SpringMockAutowiredValueApp.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        service.getValue();
    }

}

Testing the Application

Just executing the above main class will give you the following output in the concole.

${security.key}: SecurityKey

Next let’s move on to creating Junit test class that will test the @Value annotated field.

Junit Class

The following class in created under src/test/java folder.

package com.roytuts.spring.mock.autowired.field.value.junit;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;

@ExtendWith(MockitoExtension.class)
public class SpringAutowiredValueTest {

    @Mock
    private SpringServiceAutowiredField service;

    @BeforeEach
    public void setUp() {
        ReflectionTestUtils.setField(service, "securityKey", "It's a security key");
    }

    @Test
    public void testAutowiredValueField() {
        service.getValue();
        Mockito.verify(service, Mockito.times(1)).getValue();
    }

}

Generally when you mock such field that is being used for entire class. Therefore, you need to initialize such field only once or before each test case executed. So if you need to initialize only once then you can put it using @BeforeAll annotation and if you need to execute before each test method then you need to put it using @BeforeEach annotation.

Here in this example I have initialized the field using @BeforeEach annotation because I have only one test case.

Here you run the class with @ExtendWith(MockitoExtension.class) because you do not want to run integration test but mock test.

Notice how I do initialize the autowired @Value annotated field using ReflectionTestUtils.

I finally test the service class’s method and verify whether the method executed at least once using Junit’s verify() method.

Testing the Junit Test

Now run the Junit class, your Junit test will pass.

mock an autowired value field in spring with junit 5

You will get the following output in the console.

Setting field 'securityKey' of type [null] on target object [service] or target class [class com.roytuts.spring.mock.autowired.field.value.junit.SpringServiceAutowiredField$MockitoMock$1287953113] to value [It's a security key]

I have set the new value to the security key and displayed using getValue() method.

Source Code

Download

Leave a Comment