Mock an Autowired @Value field in Spring with Junit Mockito

Introduction

The below example will show you how to mock an Autowired @Value field in Spring with Junit Mockito. Generally you read some configuration values from properties file into Spring bean or component class using @Value annotated attributes but when you want to test such service or component class using Junit test class then it is required to pass values for those autowired fields.

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.

Related Posts:

Basically you need to pass three parameters as values into this method. The first parameter’s value indicates the class instance for which you want to set value to the auto-wired 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.

Therefore you are basically mocking the @Value attribute using Spring’s ReflectionTestUtils API.

The below example shows how to mock an auto-wired @Value field in Spring with Junit’s Mockito framework.

Prerequisites

Java at least 1.8, Junit 4.12 – 4.13.2, Spring 5.1.8 – 5.3.4, Mockito 2.23.4 – 3.7.7, Hamcrest 1.3 – 2.2, Gradle 5.4.1 – 6.7.1

Project Setup

Create a gradle or maven based project in your favorite IDE or tool. The name of the project is spring-mock-autowired-field-value-junit-4.

Build Script

Update the default generated build.gradle file with the following script to include the required dependencies for our application.

plugins {
    id 'java-library'
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
	compile("org.springframework:spring-core:5.1.8.RELEASE - 5.3.4")
	compile("org.springframework:spring-context:5.1.8.RELEASE - 5.3.4")
	testCompile("org.springframework:spring-test:5.1.8.RELEASE - 5.3.4")
	
	testCompile('junit:junit:4.12 - 4.13.2') {
            exclude module : 'hamcrest-core'
    }
	
	testCompile('org.hamcrest:hamcrest-core:1.3 - 2.2')
    testCompile('org.mockito:mockito-core:2.23.4 - 3.7.7')
}

Pom.xml

If you are creating maven based project then you can use the following pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<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-4</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>12</maven.compiler.source>
		<maven.compiler.target>12</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>5.3.4</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.3.4</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>5.3.4</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.13.2</version>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.hamcrest</groupId>
					<artifactId>hamcrest-core</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.hamcrest</groupId>
			<artifactId>hamcrest</artifactId>
			<version>2.2</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-core</artifactId>
			<version>3.7.7</version>
			<scope>test</scope>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
			</plugin>
		</plugins>
	</build>
</project>

Service Class

Here I will create one Spring service class that has an autowired @Value field and I will mock this field in the Junit class. I have also defined a simple method in this service class to verify the value of the auto-wired field which I initialize into Junit class.

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

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

@Service
public class SpringService {

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

	public void updateValue() {
		System.out.println(securityKey);
	}

}

Properties File

Create an application.properties file under classpath directory src/main/resources and put the below key/value pair into it.

security.key=SecurityKey

Junit Class

I will create the below Junit class for the above service class.

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 @BeforeClass annotation and if you need to execute before each class then you need to put it using @Before annotation.

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

Here I run the class with MockitoJunitRunner because I do not want to run integration test but mock test.

Notice how I do initialize the autowired 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.

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

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;

@RunWith(MockitoJUnitRunner.class)
public class SpringServiceTest {

	@Spy
	private final SpringService springJunitService = new SpringService();

	@Before
	public void setUp() {
		ReflectionTestUtils.setField(springJunitService, "securityKey", "it's a security key");
	}

	@Test
	public void testUpdateUser() throws Exception {
		springJunitService.updateValue();
		Mockito.verify(springJunitService, Mockito.times(1)).updateValue();
	}

}

You may read why I have used @Spy and Mockito.verify() in this example.

Testing the Application

Now run the Junit class, your Junit test will pass and you will get the following output in the console.

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

it's a security key

Source Code

Download

2 Thoughts to “Mock an Autowired @Value field in Spring with Junit Mockito”

  1. Sumit Bisen

    Hello Soumitra,
    I am using the above solution but didn’t work out for me. for me property value is still null when i run Junit test cases.

  2. I was looking for this solution for couple of days. Thanks for providing this solution in a perfect and simple way. Keep up doing this kinda good job.
    Thanks a lot indeed.

Leave a Comment