We have created a new Spring Boot service. As part of it we would like to improve our general testing habits by utilizing test slices more effectively (and not loading in the whole context). We are following the example of another service which has already quite effectively utilized smaller test slices.
However we have run into a mind-numbingly infuriating problem when trying to get repository tests to start working with @DataJpaTest
.
For context: there are common internal libraries which include Spring beans that need to get autowired. The common solution for solving that is using @ComponentScan
. For regular integration tests this works fine. However when trying to use smaller test slices (like @DataJpaTest
), then the annotation will try to autowire all beans, some of which are not possible to autowire in the current context.
We have solved it by removing @ComponentScan
, but then we don't have the library beans available and the application along with full integration tests won't start up.
Now this on its own would be fine and relatively expected. BUT coming back to the service mentioned earlier. They do not use @ComponentScan
at all!!! For some reason that service just autowires external library beans like magic. We have looked into pretty much everything that the internet provides about ways to get external beans and the other service is also not using anything from there.
For some reason the external beans are just available to their application context. And their @DataJpaTest
classes are also not trying to load in unnecessary (and unavailable) beans. We have talked to the other team and they are also not aware of anything special that they are doing. When they started using the libraries, then everything just worked.
So, what could possibly be the reason why 2 nearly identical services behave so differently? The question is not about getting all of the tests working (for example by filtering out the beans in the test classes). We want to understand why one service has access to the beans and the other has to run in circles and jump through hoops.
We have tried:
@ComponentScan
(full application context won't boot)To point it out then the 2 services' configuration is basically identical.
As it often happens, then as I got desperate and was writing up a question here, then a teammate noticed that the packages' domains don't match between the two services.
We had just recently went through a top level domain change. The new domain is different by a single character. The other service and the library are using the old domain in the package names, the new service is using the new domain.
So for the working service they did not require @ComponentScan
, because the default @ComponentScan
on the @SpringBootApplication
was matching the library beans as well.
That default @ComponentScan
has filters on which seem to filter out the unnecessary beans during tests.
So the easy fix was to just add the default filters to the new service's @ComponentScan
as well.
@ComponentScan(
value = {"old.domain.package.library.*", "new.domain.package.*"},
excludeFilters = {
@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
),
@Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)
})