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
Thanks, it will work but, what about security like what if, we need to hide the value?
Thank you so much!…..I had looked it for many times .Thanks once again, You are great👌.
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.
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.