Search code examples
javaspringunit-testingautowiredjavax-inject

Autowiring a javax.inject.provider in a unit-test with spring context


While playing around with the javax provider, I have created a spring configuration file with the following two Beans:

@Bean
Provider<Map<Integer, JsonNode>> worldMapDataProvider() {
  //code here
}

@Bean
Provider<List<Building>> buildingsDataProvider() {
  //code here
}

I am injecting these two beans in two different services like so:

@Resource
private Provider<Map<Integer, JsonNode>> worldMapDataProvider;

@Resource
private Provider<List<Building>> buildingsDataProvider;

The implementation works as expected and my depending controllers also return the data in the anticipated format. Now I wanted to add a few unit-tests for my implementation, by autowiring the providers "into my test-setup".

The configuration for my test-class which worked at the end looks as follows:

@SpringBootTest(classes={ResourceProviders.class, ResourceProviderUtils.class, Beans.class})
class ResourceProvidersTest {

ResourceProvider is what I want to use; this class depends on ResourceProviderUtils which in turn depends on a jackson objectMapper which I have defined in Beans. Thus, the required dependency-chain is ResourceProviders -> ResourceProviderUtils -> Beans

Now, to get to my question.

I was trying to create an annotation-based solution for my test without using @SpringBootTest. To be precise, this is the configuration which I expected to work:

@ExtendWith(SpringExtension.class)
@ComponentScan("{myBasePackage}")

I injected the two Beans exactly the same way as I did in my services with the @Resource annotation. But in the test-case, I get the following exception:

 No qualifying bean of type 'java.util.List<{myBasePackage}.game.data.model.economy.buildings.Building>' available

You can see that it is not looking for a bean of type Provider<List>, but for one of type List. I have never delcared such a bean though and as such do not require it anywhere either. I always inject the provider into my services (and this test-case) and access the data using provider.get().

I have a feeling that the provider is implicitly being resolved somehow, but this is just an assumption. Could anybody explain to me what exactly is happening here and why? I would like to get a better understanding of why this is happening with the given configuration.


Solution

  • @ComponentScan does not work with @ExtendWith, use @ContextConfiguration instead

    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes={ResourceProviders.class, ResourceProviderUtils.class, Beans.class})
    public class ResourceProvidersTest {
     @Autowire ResourceProviders resourceProviders;
     @Autowire ResourceProviderUtils resourceProviderUtil;
     @Autowire Beans beans;
     ...
    }
    

    Or use @SpringJUnitConfig; this annotation combines @ExtendWith(SpringExtension.class) with @ContextConfiguration

    @SpringJUnitConfig(classes={ResourceProviders.class, ResourceProviderUtils.class, Beans.class})
    public class ResourceProvidersTest {
     @Autowire ResourceProviders resourceProviders;
     @Autowire ResourceProviderUtils resourceProviderUtil;
     @Autowire Beans beans;
     ...
    }