I am trying to get some junit tests with Mockito to work in a SprinBoot application.
Now my Service has some variable that gets filled from the application.properties
by means of @Value
annotation:
@Component
@Slf4j
public class FeatureFlagService {
@Autowired
RestTemplate restTemplate;
@Value("${url.feature_flags}")
String URL_FEATURE_FLAGS;
// do stuff
}
I am trying to test this by using TestPropertySource
like so:
@ExtendWith(MockitoExtension.class)
@TestPropertySource(properties = { "${url.feature_flags} = http://endpoint" })
class FeatureFlagServiceTests {
@Mock
RestTemplate restTemplate;
@InjectMocks
FeatureFlagService featureFlasgService;
@Test
void propertyTest(){
Assertions.assertEquals(featureFlasgService.URL_FEATURE_FLAGS, "http://endpoint");
}
However the property does not get filled and remains null
.
There are a bunch of tpoics on this, but I have not been able to piece together a solution. I saw solutions suggesting @SpringBootTest
, but then it seems to want to do an integration test, spinning up the service, which fails because it can not connect to DB. So that is not what I am looking for.
I also saw solutions suggesting I make a PropertySourcesPlaceholderConfigurer
bean.
I tried that by putting :
@Bean
public static PropertySourcesPlaceholderConfigurer propertiesResolver() {
return new PropertySourcesPlaceholderConfigurer();
}
In my Application.java
. But that is not working / not enough. I am not sure if I was supposed to do that differently, or if there is more there that I do not know.
Please advice.
CodePudding user response:
You can use @SpringBootTest
without running the whole application by passing it the class that contains the @Value
but you have to use Spring's extension @ExtendWith({SpringExtension.class})
which is included inside @SpringBootTest
and by that using Spring's MockBean
instead of @Mock
and @Autowired
for autowiring the bean like this:
@SpringBootTest(classes = FeatureFlagService.class)
class FeatureFlagServiceTests {
@MockBean
RestTemplate restTemplate;
@Autowired
FeatureFlagService featureFlasgService;
@Test
void propertyTest(){
Assertions.assertEquals(featureFlasgService.URL_FEATURE_FLAGS, "http://endpoint");
}
CodePudding user response:
I recommend you to try this approach. Just need a slightly refactoring and add a package-private constructor to your FeatureFlagService
.
FeatureFlagService.java
@Component
@Slf4j
public class FeatureFlagService {
private final RestTemplate restTemplate;
private final String URL_FEATURE_FLAGS;
// package-private constructor. test-only
FeatureFlagService(RestTemplate restTemplate, @Value("${url.feature_flags}") String flag) {
this.restTemplate = restTemplate;
this.URL_FEATURE_FLAGS = flag;
}
// do stuff
}
Then prepare your mocks and url, and inject them by the constructor-injection
.
FeatureFlagServiceTests.java
public class FeatureFlagServiceTests {
private FeatureFlagService featureFlagService;
@Before
public void setup() {
RestTemplate restTemplate = mock(RestTemplate.class);
// when(restTemplate)...then...
String URL_FEATURE_FLAGS = "http://endpoint";
featureFlagService = new FeatureFlagService(restTemplate, URL_FEATURE_FLAGS);
}
@Test
public void propertyTest(){
Assertions.assertEquals(featureFlasgService.getUrlFeatureFlags(),
"http://endpoint");
}
}
The significant advantage is, your FeatureFlagServiceTests
becomes very simple to read and trivial to test. You don't need magic annotation of Mockito anymore.