如何在 SpringJunit4TestRunner 中将 @ComponentScan 与特定于测试的 ContextConfigurations 一起使用?

新手上路,请多包涵

我正在测试一个 Spring Boot 应用程序。我有几个测试类,每个测试类都需要一组不同的模拟或其他定制的 bean。

这是设置的草图:

源/主/java:

 package com.example.myapp;

@SpringBootApplication
@ComponentScan(
        basePackageClasses = {
                MyApplication.class,
                ImportantConfigurationFromSomeLibrary.class,
                ImportantConfigurationFromAnotherLibrary.class})
@EnableFeignClients
@EnableHystrix
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

package com.example.myapp.feature1;

@Component
public class Component1 {
    @Autowired
    ServiceClient serviceClient;

    @Autowired
    SpringDataJpaRepository dbRepository;

    @Autowired
    ThingFromSomeLibrary importantThingIDontWantToExplicitlyConstructInTests;

    // methods I want to test...
}

源/测试/java:

 package com.example.myapp;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@ActiveProfiles("test")
public class Component1TestWithFakeCommunication {

    @Autowired
    Component1 component1; // <-- the thing we're testing. wants the above mock implementations of beans wired into it.

    @Autowired
    ServiceClient mockedServiceClient;

    @Configuration
    static class ContextConfiguration {
        @Bean
        @Primary
        public ServiceClient mockedServiceClient() {
            return mock(ServiceClient.class);
        }
    }

    @Before
    public void setup() {
        reset(mockedServiceClient);
    }

    @Test
    public void shouldBehaveACertainWay() {
        // customize mock, call component methods, assert results...
    }
}

package com.example.myapp;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@ActiveProfiles("test")
public class Component1TestWithRealCommunication {

    @Autowired
    Component1 component1; // <-- the thing we're testing. wants the real implementations in this test.

    @Autowired
    ServiceClient mockedServiceClient;

    @Before
    public void setup() {
        reset(mockedServiceClient);
    }

    @Test
    public void shouldBehaveACertainWay() {
        // call component methods, assert results...
    }
}

上述设置的问题在于 MyApplication 中配置的组件扫描获取了 Component1TestWithFakeCommunication.ContextConfiguration,因此即使在我想要真正的 ServiceClient 实现的 Component1TestWithRealCommunication 中,我也得到了一个模拟 ServiceClient。

尽管我可以在两个测试中使用@Autowired 构造函数并自己构建组件,但有足够多的复杂设置的东西,我宁愿为我设置 Spring TestContext(例如,Spring Data JPA 存储库、库中的组件在从 Spring 上下文中提取 bean 的应用程序之外,等等)。在测试中嵌套一个可以在 Spring 上下文中本地覆盖某些 bean 定义的 Spring 配置感觉应该是一种干净的方法;唯一的缺点是这些嵌套配置最终会影响所有基于 MyApplication 配置的 Spring TestContext 测试(该组件扫描应用程序包)。

如何修改我的设置,以便在每个测试类中只有几个本地覆盖的 bean 仍然为我的测试获得“大部分真实”的 Spring 上下文?

原文由 Jonathan Fuerth 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 828
2 个回答

通过引入仅适用于当前测试类的新 fake-communication _配置文件_,以下内容应该可以帮助您实现目标。

 @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@ActiveProfiles({"test", "fake-communication"})
public class Component1TestWithFakeCommunication {

    // @Autowired ...

    @Profile("fake-communication")
    @Configuration
    static class ContextConfiguration {
        @Bean
        @Primary
        public ServiceClient mockedServiceClient() {
            return mock(ServiceClient.class);
        }
    }
}

原文由 Sam Brannen 发布,翻译遵循 CC BY-SA 3.0 许可协议

我会做几件事:

  1. 将您的测试类移动到不同的包中以避免 @ComponentScan 它们。
  2. Component1TestWithFakeCommunication 中,将 @SpringApplicationConfiguration(classes = MyApplication.class) 更改为 @SpringApplicationConfiguration(classes = {MyApplication.class, Component1TestWithFakeCommunication.ContextConfiguration.class})

这应该为 Spring 提供足够的信息来模拟测试 bean,但它应该防止运行时 ApplicationContext 也注意到您的测试 bean。

原文由 Josh Ghiloni 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题