小编典典

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

spring-boot

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

这是设置的草图:

src / main / 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...
}

src / 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,因此,即使在Component1TestWithRealCommunication中,我也想要一个真实的ServiceClient来模拟ServiceClient。

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

如何修改我的设置,以便在每个测试类中只有几个本地重写的bean的情况下仍然为测试提供“最真实的” Spring上下文?


阅读 532

收藏
2020-05-30

共1个答案

小编典典

以下内容将通过引入一个仅适用于当前测试类的新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);
        }
    }
}
2020-05-30