如何在多Gradle项目中的JUnit Spring上下文中加载资源属性?

时间:2017-11-06 21:36:49

标签: java spring spring-mvc spring-boot gradle

我有以下项目树:

├── 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时弹簧是否以某种方式限制了类路径分辨率?

  • 我还没有办法在application-test.yml中从测试范围中初始化的配置@Bean内阅读childA childB,这怎么可能?

1 个答案:

答案 0 :(得分:2)

您使用AnnotationConfigContextLoader代替(默认)SpringBootContextLoader是否有任何特殊原因?您遇到的问题不是由类路径中缺少文件引起的(您可以将application-test.yaml复制到任何具有相同结果的src/main/resourcessrc/test/resources,但事实是AnnotationConfigContextLoader不会使用负责配置上下文的ConfigFileApplicationListener来加载来自众所周知的文件位置的属性(例如您的application-{profile}.yaml)。

您可以轻松比较使用每个加载器时加载的属性。首先,您可以检查AnnotationConfigContextLoader的作用 - 只需在AbstractGenericContextLoader.java文件的第128行放置一个断点,并在您喜欢的IDE中运行调试器:

enter image description here

接下来,您可以调查变量context - > environment - > propertySources - > propertySourceList。您将找到5个房产来源:

enter image description here

他们都没有从application.ymlapplication.properties等配置文件中加载属性。

现在让我们做同样的事情但SpringBootContextLoader课程。首先删除

loader = AnnotationConfigContextLoader.class
<{1>}中的

并在SpringApplication.java文件中的第303行放置一个断点:

enter image description here

我们在应用程序上下文刷新之前是正确的。现在让我们调查变量MyEntityTest - &gt; context - &gt; environment - &gt; propertySources

enter image description here

我们可以看到的第一个区别是,现在我们有7个属性源而不是前一个示例中的5个属性源。最重要的是 - propertySourceList就在这里。此类使应用程序上下文能够识别ConfigFileApplicationListener.ConfigurationPropertySources属性文件。

enter image description here

因此,您可以看到它只是使用正确的上下文加载器的问题。取代

application-{profile}.yaml

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

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

因为使用@ContextConfiguration(classes = { ChildCConfig.class }) 注释时此加载器是默认加载器,您将使测试像魅力一样传递。我希望它有所帮助。