How to load resource properties in a JUnit Spring context in a multi Gradle project?

I have the following project tree:

β”œβ”€β”€ app β”‚  β”œβ”€β”€ build.gradle β”‚  └── src β”‚  β”œβ”€β”€ main β”‚  β”‚  β”œβ”€β”€ java β”‚  β”‚  β”‚  └── child β”‚  β”‚  β”‚  └── app β”‚  β”‚  β”‚  └── Application.java β”‚  β”‚  └── resources β”‚  β”‚  └── application-default.yaml β”‚  └── test β”‚  └── java β”‚  └── child β”‚  └── app β”‚  └── ApplicationTest.java β”œβ”€β”€ build.gradle β”œβ”€β”€ childA β”‚  β”œβ”€β”€ build.gradle β”‚  └── src β”‚  └── main β”‚  └── java β”‚  └── child β”‚  └── a β”‚  β”œβ”€β”€ BaseGreeterImpl.java β”‚  β”œβ”€β”€ ChildAConfig.java β”‚  β”œβ”€β”€ Greeter.java β”‚  └── MySpringProperties.java β”œβ”€β”€ childB β”‚  β”œβ”€β”€ build.gradle β”‚  └── src β”‚  └── main β”‚  └── resources β”‚  β”œβ”€β”€ application-test.yaml β”‚  └── childB.properties β”œβ”€β”€ childC β”‚  β”œβ”€β”€ build.gradle β”‚  └── src β”‚  β”œβ”€β”€ main β”‚  β”‚  β”œβ”€β”€ java β”‚  β”‚  β”‚  └── child β”‚  β”‚  β”‚  └── c β”‚  β”‚  β”‚  β”œβ”€β”€ ChildCConfig.java β”‚  β”‚  β”‚  └── PropertyGreeterImpl.java β”‚  β”‚  └── resources β”‚  β”‚  └── childc.properties β”‚  └── test β”‚  └── java β”‚  └── child β”‚  └── c β”‚  β”œβ”€β”€ TestYamlImport.java β”‚  └── TestGreeter.java └── settings.gradle 

I have the following test class:

 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { ChildCConfig.class }, loader = AnnotationConfigContextLoader.class) @ActiveProfiles("test") @SpringBootTest public class TestYamlImport { @Autowired private MySpringProperties properties; @Test public void readChildAYaml() { assertThat(properties.getName()).isEqualTo("it-is-another-thing"); } } 

Expected

I expect properties.getName() read the value from the childB resource in childB / src / main / resources / application-test.yaml .

Result

I get null

Play

GitHub: https://github.com/kopax/adk/tree/adk-spring

One liner:

 git clone git@github.com :kopax/adk.git && cd adk && git checkout adk-spring && ./gradlew build --info 

Question

In a reproduced project, which proves with childC / src / test / java / childC / TestGreeter.java import, that this is not a problem with the classpath .

So here are my questions:

  • Is spring a class path permission restriction when using @ConfigurationProperties ?

  • I did not find a way to read my application-test.yml in the @Bean configuration initialized in childA from the scope of the childB check as possible

+7
java spring spring-boot spring-mvc gradle
source share
1 answer

Is there any specific reason why you use AnnotationConfigContextLoader instead of (by default) SpringBootContextLoader ? The problem you are facing is not caused by the lack of a file in the classpath (you can copy application-test.yaml to either src/main/resources or src/test/resources with the same result), but the fact that AnnotationConfigContextLoader not uses the ConfigFileApplicationListener , which is responsible for setting the context, loading properties from well-known file locations (for example, application-{profile}.yaml in your case).

You can easily compare which properties load when using each bootloader. First, you can check what AnnotationConfigContextLoader does - just put a breakpoint on line 128 of the AbstractGenericContextLoader.java file and run the debugger in your favorite IDE:

enter image description here

Next, you can examine the variable context β†’ environment β†’ propertySources β†’ propertySourceList . You will find 5 sources of property:

enter image description here

None of them load properties from configuration files, such as application.yml or application.properties .

Now do the same, but with the SpringBootContextLoader class. Delete first

 loader = AnnotationConfigContextLoader.class 

in MyEntityTest and place a breakpoint on line 303 in the SpringApplication.java file:

enter image description here

Here we are right before updating the application context. Now consider the variable context β†’ environment β†’ propertySources β†’ propertySourceList :

enter image description here

The first difference that we see is that now we have 7 sources of properties instead of 5, as in the previous example. And most importantly - ConfigFileApplicationListener.ConfigurationPropertySources here. This class makes the application context aware of the existence of the application-{profile}.yaml .

enter image description here

So you can see that it is only a matter of using the right context loader. Replace

 @ContextConfiguration(classes = { ChildCConfig.class }, loader = AnnotationConfigContextLoader.class) 

from

 @ContextConfiguration(classes = { ChildCConfig.class }, loader = SpringBootContextLoader.class) 

or

 @ContextConfiguration(classes = { ChildCConfig.class }) 

since this bootloader is standard when using the @SpringBootTest annotation, and you will make your test pass like a charm. Hope this helps.

+2
source share

All Articles