Populating Spring @Value during Unit Test
If possible I would try to write those test without Spring Context. If you create this class in your test without spring, then you have full control over its fields.
To set the @value
field you can use Springs ReflectionTestUtils
- it has a method setField
to set private fields.
@see JavaDoc: ReflectionTestUtils.setField(java.lang.Object, java.lang.String, java.lang.Object)
How to Pass @Value to a @Component for Spring Unit Testing
You can inject the @Value in test class by ReflectionTestUtils. Load container only in case of Controllers. For writing test cases for services and dao you don't need to load the spring container.
public class TestClass{
private @InjectsMock ServiceClass service;
@BeforeAll
public void setUp(){
ReflectionTestUtils.setField(service, "someString", "someValue");
}
//your test cases over here.
}
JUnit testing of spring boot @value variable
I assume, you have already managed to mock 'userType', so in order to mock 'userTypeSpecific', you can use Spring's ReflectionTestUtils.setField method to mock @value variables.
You can find details here:
https://www.briandupreez.net/2011/04/little-spring-gem-reflectiontestutils.html
@Value resolving to null when running things from unit test
Because all the @MockitoJUnitRunner
, @InjectMocks
and @Mock
are Mockito stuffs and they do not know anything about Spring. Hence they do not understand what @Value
does and will not inject its value. The spring container even do not start in you case.
If you are using spring-boot and want Spring to inject this value , you can consider using spring-boot-starter-test
starter and use its @MockBean
to configure the Mockito mock :
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestBidService {
@Autowired
private BidServiceImpl bidService;
@MockBean
RestTemplate restTemplate;
@Test
public void testFindAllReturnsListOfBids(){
///
}
}
But it is an integration test as it will start up the whole spring container , so it is slower than the true unit test.
If you want the test to run as fast as possible , don't rely on Spring to inject that value for you. Simply set up by yourself:
@RunWith(MockitoJUnitRunner.class)
public class TestBidService {
@Mock
RestTemplate restTemplate;
@Test
public void testFindAllReturnsListOfBids(){
BidServiceImpl bidService = new BidServiceImpl(restTemplate , "http://127.0.0.1/");
////
}
}
Spring Boot Unit Test @Value from .properties File gives NullPointerException
Thanks to @shazin's answer and some of my own research I've been able to solve the problem.
Basically, there needs to be compatibility between the test runner class specified in @RunWith
and the annotations for the Mockito mocks. We want to test the Service
class:
Service Class:
@Component
public class Service {
@Autowired
Environment environment;
public String getProperty() {
return environment.getProperty("prop");
}
}
If you're using @RunWith(MockitoJUnitRunner.class)
, you can use the @InjectMocks
and @Mock
annotations like below. Whatever is @Autowired
in Service
will be auto-wired with the mocks:
Test Class with MockitoJUnitRunner
:
@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
@InjectMocks
Service service;
@Mock
Environment mockEnvironment;
@Before
public void before() {
Mockito.when(mockEnvironment.getProperty("prop")).thenReturn("some-test-value")
}
}
But you can't auto-wire anything in the test class itself. That requires a Spring Context (a Spring Context is needed to manage the beans which get auto-wired into objects). That's where @RunWith(SpringRunner.class)
comes into the picture. You can use it to run a test case with a dedicated Spring context (you'll notice the test case logs showing a new Spring application being booted up for every test class with the @RunWith(SpringRunner.class)
annotation). You'll also need to provide the Configuration details with the @SpringBootTest
annotation.
The caveat is that a test class with @RunWith(SpringRunner.class)
won't understand the @InjectMocks
and @Mock
annotations; you'll have to use the @MockBean
annotation. This will effectively modify the Spring context by replacing beans with their mocks; anything with the @Autowired
annotation will get auto-wired with the mock beans automatically:
Test Class with SpringRunner
:
@RunWith(SpringRunner.class)
@SpringBootTest(classes=Application.class)
public class ServiceTest {
@Autowired
Service service;
@MockBean
Environment mockEnvironment;
@Before
public void before() {
Mockito.when(mockEnvironment.getProperty("prop")).thenReturn("some-test-value")
}
}
So...using the @RunWith(SpringRunner.class)
didn't achieve anything except change the names of the annotations (@InjectMocks
-> @Autowired
, and @Mock
-> @MockBean
), right? Wrong. Using SpringRunner
gives you the power of auto-wiring components within your test case. So if you want to use an actual Environment
(not a mock one), you can do that as well; just auto-wire it in from the dedicated Spring context:
Test Class with SpringRunner
and @Autowired
Environment:
@RunWith(SpringRunner.class)
@SpringBootTest(classes=Application.class)
public class ServiceTest {
@Autowired
Service service;
@Autowired
Environment environment;
@Test
public void testServiceGetProperty() {
assertEquals(environment.getProperty("prop"), service.getProperty("prop");
}
}
And that solves the problem.
Value annotation not working in Junit test
Following works for me. It picks up value from the application.properties file.
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
public class ValueAnnotationTest {
@Value("${myUrl}")
private String myUrl;
@Test
public void test1() throws Exception {
assertThat(myUrl).isEqualTo("http://test.com");
}
}
From Spring Boot docs:
Using
ConfigFileApplicationContextInitializer
alone does not provide
support for@Value("${…}")
injection. Its only job is to ensure that
application.properties
files are loaded into Spring’s Environment. For
@Value
support, you need to either additionally configure a
PropertySourcesPlaceholderConfigurer
or use@SpringBootTest
, which
auto-configures one for you.
Spring Boot unit test executing the main class
I ran into this myself. Its a counter-intuitive way Spring works. I solved it by putting my test application in a package outside of the package which has the main application.
So, if your main application is my.app.SampleMain, try putting your test class in my.test.SampleTest.
Related Topics
Jtable Model Listener Detects Inserted Rows Too Soon (Before They Are Drawn)
Singleton with Arguments in Java
How to Sum Digits of an Integer in Java
What Is Difference Between Crudrepository and JPArepository Interfaces in Spring Data JPA
How to Update Path Variable Permanently from Windows Command Line
List All Files from a Directory Recursively with Java
Where to Find Source Code for Java.Lang Native Methods
_ (Underscore) Is a Reserved Keyword
Autocomplete with Java , Redis, Elastic Search , Mongo
Good Reasons to Prohibit Inheritance in Java
Compile-Time Constants and Variables
Why Are the Rsa-Sha256 Signatures I Generate with Openssl and Java Different
How to Keep a Scanner from Throwing Exceptions When the Wrong Type Is Entered
How to Get the Latest Jre/Jdk as a Zip File Rather Than Exe or Msi Installer
How to Create an Asynchronous Http Request in Java
Configure Hibernate (Using JPA) to Store Y/N for Type Boolean Instead of 0/1