'@TestPropertySource is not helping to fetch configuration property values
In the following test code snippet, values of number_of_days.last and number_of_months.plan are not getting fetched from the configuration file.Please check and see what could be the reason.When i remove @Value annotation from my service class ShiftPlanService.java and just initialize the values there with the required values,the test passes.
@ExtendWith(MockitoExtension.class)
@ContextConfiguration(classes=SpringbootMysqlExampleApplication.class)
@TestPropertySource(locations="src/main/resources/application.properties",properties= {"number_of_days.last= 7","number_of_months.plan= 2"})
class ShiftPlanServiceTest {
@Mock
ShiftPlanRepo mockedSpr;
@Mock(lenient = true)
ShiftDetailsRepo mockedSdr;
@Mock(lenient = true)
EmployeeDetailsRepo mockedEdr;
@Spy
ShiftPlanService sps;
@BeforeEach
public void setUp() {
when(mockedSdr.findShiftNameById(1)).thenReturn("Morning");
when(mockedSdr.findShiftNameById(2)).thenReturn("Afternoon");
when(mockedEdr.getNameById(0)).thenReturn("Amit");
when(mockedEdr.getNameById(1)).thenReturn("Anupam");
when(mockedEdr.getNameById(2)).thenReturn("Chirag");
when(mockedEdr.getNameById(3)).thenReturn("Rashmi");
when(mockedEdr.count()).thenReturn(4L);
}
@Test
public void testCreateShiftPlan() {
sps.createShiftPlan(4, 1, 2020);
verify(mockedSpr, times(36)).save(any(ShiftPlan.class));
verifyNoMoreInteractions(mockedSpr);
}
}
application.properties file is as follows-
server.port=8104
number_of_days.last= 7
number_of_months.plan= 2
spring.datasource.url=<<sensitive info>>
spring.datasource.username=<sensitive info>
spring.datasource.password=<sensitive info>
#Keep the connection alive while idle for a long time
spring.datasource.testWhileIdle= true
spring.datasource.validationQuery= SELECT 1
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager)
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
In the ShiftPlanService class, i have
@Value("${number_of_days.last}")
public int ndl;
@Value("${number_of_months.plan}")
public int nm;
Solution 1:[1]
I think you are intending to use a real instance of ShiftPlanService and have mocks injected. You need to have Spring autowire the ShiftPlanService into your test and tell it to inject the mocks like this:
@Autowired
@InjectMocks
ShiftPlanService sps;
Though you may consider just instantiating ShiftPlanService yourself in your setup method and just pass your mocks and set the other properties on the ShiftPlanService instead.
Solution 2:[2]
You are confusing Mockito injection with Spring injection. @Value
is a Spring concept and will only be injected when Spring manages the bean, but the instance of ShiftPlanService
you have in your test is injected by Mockito
using @Spy
(which as has been pointed out you don't really need).
My recommendation would be to decide what you want - a unit test with mocks, or a full-blown Spring test with the application context running. It seems to me that your intent is to write a unit test with everything mocked out, in which case:
- remove
@ContextConfiguration
and@TestPropertySource
(you don't need those for unit tests) - use
@InjectMocks
instead of@Spy
onShiftPlanService sps
- it will most likely do what you want, depending on howShiftPlanService
is implemented - manually set the config values you need in
sps
; you can add setters for those for the test to use; if the unit test is in the same package as the class - which is a good practice - they can be package-private too - because in production Spring will autowire them for you, so you only need them for the test - oh, and keep the
@Value
annotation in yourShiftPlanService
- it's needed for production - as explained above
Solution 3:[3]
We invented a Mockito extension that allows for easy injection of String/Integer/Boolean properties. Checkout the readme, it's super easy to use and works along with @InjectMocks
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Jonathan S. Fisher |