如何在多 Gradle 项目的 JUnit Spring 上下文中加载资源属性?
Posted
技术标签:
【中文标题】如何在多 Gradle 项目的 JUnit Spring 上下文中加载资源属性?【英文标题】:How to load resource properties in a JUnit Spring context in a multi Gradle project? 【发布时间】:2018-04-19 03:57:22 【问题描述】:我有以下项目树:
├── 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
我有以下测试类:
@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");
预期
我希望properties.getName()
能够从childB/src/main/resources/application-test.yaml 中的资源childB
中读取值。
结果
我收到null
复制
GitHub:https://github.com/kopax/adk/tree/adk-spring
一个班轮:
git clone git@github.com:kopax/adk.git && cd adk && git checkout adk-spring && ./gradlew build --info
问题
在复制项目中有一个名为 childC/src/test/java/childC/TestGreeter.java 的测试,通过 childB.properties
导入证明 这不是类路径问题。
所以这是我的问题:
在使用@ConfigurationProperties
时,spring 是否会以某种方式限制类路径分辨率?
在childA
中从childB
的测试范围 初始化的配置@Bean
中,我还没有找到读取我的application-test.yml
的方法,这怎么可能?
【问题讨论】:
【参考方案1】:您使用AnnotationConfigContextLoader
而不是(默认)SpringBootContextLoader
有什么特别的原因吗?您面临的问题不是由类路径中缺少文件引起的(您可以将application-test.yaml
复制到任何src/main/resources
或src/test/resources
具有相同的结果)但AnnotationConfigContextLoader
不使用ConfigFileApplicationListener
的事实是负责通过从众所周知的文件位置加载属性来配置上下文(如您的情况下为application-profile.yaml
)。
您可以轻松比较使用每个加载器时加载的属性。首先,您可以检查 AnnotationConfigContextLoader
的功能 - 只需在 AbstractGenericContextLoader.java 文件的第 128 行放置一个断点,然后在您最喜欢的 IDE 中运行调试器:
接下来你可以调查变量context
-> environment
-> propertySources
-> propertySourceList
。您将找到 5 个属性来源:
它们都不从application.yml
或application.properties
等配置文件中加载属性。
现在让我们做同样的事情,但使用SpringBootContextLoader
类。首先删除
loader = AnnotationConfigContextLoader.class
在MyEntityTest
中并在 SpringApplication.java 文件的第 303 行放置一个断点:
在刷新应用程序上下文之前,我们就到了这里。现在让我们研究变量context
-> environment
-> propertySources
-> propertySourceList
:
我们可以看到的第一个区别是,现在我们有 7 个属性源,而不是之前示例中的 5 个。最重要的是——ConfigFileApplicationListener.ConfigurationPropertySources
就在这里。此类使应用程序上下文知道application-profile.yaml
属性文件的存在。
如您所见,这只是使用正确的上下文加载器的问题。替换
@ContextConfiguration(classes = ChildCConfig.class , loader = AnnotationConfigContextLoader.class)
与
@ContextConfiguration(classes = ChildCConfig.class , loader = SpringBootContextLoader.class)
或
@ContextConfiguration(classes = ChildCConfig.class )
因为这个加载器是使用@SpringBootTest
注释时的默认加载器,你会让你的测试像魅力一样通过。希望对你有帮助。
【讨论】:
没有特别的原因......非常感谢它真的有帮助,也感谢您提供调试信息!以上是关于如何在多 Gradle 项目的 JUnit Spring 上下文中加载资源属性?的主要内容,如果未能解决你的问题,请参考以下文章
使用 gradle 进行 android 项目的 junit 测试
如何使用 Gradle 中的本地 JUnit Jar 而不是 Maven Central?