I'm currently migrating a Spring Boot app to version 3.4.
In this version, @MockBean
and @SpyBean
are deprecated and replaced by @MockitoBean
and @MockitoSpyBean
I've made the changes in my class annotated with @TestConfiguration
, and since then my SpringBootTests are failing at the initialization phase.
This is how my configuration class looks like:
@TestConfiguration
public class IntegrationTestConfig {
@MockitoSpyBean
private LanguageRepository languageRepository;
@PostConstruct
void setUp() {
when(languageRepository.findAllCodes()).thenReturn(List.of("fr", "en"));
}
}
This configuration is included via a custom meta-annotation, like this:
@Retention(RetentionPolicy.RUNTIME)
@SpringBootTest(classes = {IntegrationTestConfig.class, SpringSecurityTestConfig.class})
@ActiveProfiles("test")
@Sql(scripts = "classpath:sql/clearTables.sql", executionPhase = ExecutionPhase.AFTER_TEST_METHOD)
@AutoConfigureMockMvc
public @interface IntegrationTest {
}
Since making this change, I now encounter the following error during @PostConstruct
execution:
java.lang.NullPointerException: Cannot invoke "package.whatever.LanguageRepository.findAllCodes()" because "this.languageRepository" is null
The error does not occur if I revert to the deprecated API (@SpyBean
). Everything works fine with the old annotations.
My questions:
@BeforeEach
setup?Edit: Giving context
This @SpyBean
is used to mock something only done at application startup where an external WS call is made.
@Bean
ApplicationRunner fetchTranslations(LocalazyService translationService) {
log.info("Initializing translations...");
return ignored -> translationService.updateTranslationsWithCdn();
}
So, as of late, I haven't found any solution similar to the @PostConstruct
one.
In the end, here's how I made it work without inheritance or @BeforeEach
setups:
@SpyBean
annotations with a @MockitoSpyBean
one inside my custom IntegrationTest
annotation (see: documentation).data.sql
file with inserts, located in the src/test/resources
folder. I no longer need to spy on a repository.org.wiremock.integrations:wiremock-spring-boot
This is what the custom IntegrationTest
annotation looks like:
@Retention(RetentionPolicy.RUNTIME)
@SpringBootTest(classes = SpringSecurityTestConfig.class)
@ActiveProfiles("test")
@Sql(scripts = "classpath:sql/clearTables.sql", executionPhase = ExecutionPhase.AFTER_TEST_METHOD)
@AutoConfigureMockMvc
@EnableWireMock({
@ConfigureWireMock(name = "localazy-client", baseUrlProperties = "i18n.localazy.cdnUrl", filesUnderClasspath = "wiremock/localazy-client")
})
@MockitoSpyBean(types = {JavaMailSender.class, LocalazyService.class})
public @interface IntegrationTest {
}
Using Wiremock is a bit heavier than I would have liked, and I might lose a few seconds when running tests individually, but it's a compromise I can accept.
I don't need the IntegrationTestConfig
configuration class anymore, as it's now empty.