如何为不同的应用程序运行相同的 SpringBootTests

Posted

技术标签:

【中文标题】如何为不同的应用程序运行相同的 SpringBootTests【英文标题】:How to run the same SpringBootTests for different applications 【发布时间】:2018-06-22 11:48:50 【问题描述】:

我有一个 SpringBoot 多模块应用程序,类似这样:

核心 customer1 -> 取决于核心 customer2 -> 依赖于核心

我想为两者编写集成测试,但我不想复制我的核心测试代码。现在我有了一个带有 SpringBootTest(classes = Customer1Application.class) 的抽象类和很多测试类,主要是测试核心功能。

@ContextConfiguration
@SpringBootTest(classes = Customer1Application.class)
@AutoConfigureMockMvc
public abstract class AbstractSpringBootTest


@Autowired
protected MockMvc                               mockMvc;

@Autowired
protected Validator                             validator;

...

我想检查 Customer2 应用程序中的更改是否破坏了核心功能,因此我想使用 @SpringBootTest(classes = Customer2Application.class) 注释运行这些测试。

如何在注解中配置应用程序类?有没有办法在我的其他应用程序上下文中运行测试,而无需手动更改注释或复制所有步骤?

【问题讨论】:

【参考方案1】:

我不知道它是否会起作用,但我会尝试从AbstractSpringBootTest 中删除@SpringBootTest,然后定义两个测试类,如下所示:

@SpringBootTest(classes = Customer1Application.class)
class Customer1ApplicationSpringBootTest extends AbstractSpringBootTest 

@SpringBootTest(classes = Customer2Application.class)
class Customer2ApplicationSpringBootTest extends AbstractSpringBootTest 

编辑:

所以我挖掘了 Spring Boot 的源代码并想出了this solution。

基本上为了能够使用系统属性或属性文件来配置应该测试哪个@SpringBootApplication,您需要将类org.springframework.boot.test.context.SpringBootConfigurationFinder的源复制到您自己的测试源根目录和编辑方法private Class<?> scanPackage(String source)以查看像这样的东西(你当然不必使用 Lombok):

private Class<?> scanPackage(String source) 
    while (!source.isEmpty()) 
        val components = this.scanner.findCandidateComponents(source);
        val testConfig = System.getProperties();
        val testConfigFile = "test-config.properties";
        val applicationClassConfigKey = "main.application.class";
        try 
            testConfig.load(this.getClass().getResourceAsStream("/" + testConfigFile));
         catch (IOException e) 
            logger.error("Error reading configuration file: , using default algorithm", testConfigFile);
        
        if (testConfig.containsKey(applicationClassConfigKey)) 
            if (!components.isEmpty() && testConfig.containsKey(applicationClassConfigKey) && testConfig.getProperty(applicationClassConfigKey) != null) 
                boolean found = false;
                val configClassName = testConfig.getProperty(applicationClassConfigKey);
                for (BeanDefinition component: components) 
                    if (configClassName.equals(component.getBeanClassName())) 
                        found = true;
                        break;
                    
                
                Assert.state(found,
                    () -> "Found multiple @SpringBootConfiguration annotated classes "
                        + components + ", none of which are of type " + configClassName);
                return ClassUtils.resolveClassName(
                    configClassName, null);
            
         else 
            if (!components.isEmpty()) 
                Assert.state(components.size() == 1,
                    () -> "Found multiple @SpringBootConfiguration annotated classes "
                                    + components);
                return ClassUtils.resolveClassName(
                     components.iterator().next().getBeanClassName(), null);
            
        
        source = getParentPackage(source);
    
    return null;

检查整个项目的link。

【讨论】:

是的,它可以工作,但我需要复制所有的测试类。例如:@SpringBootTest(classes = Customer1Application.class) class CoreFunctionXYTestWithCustomer1 extends AbstractSpringBootTest @SpringBootTest(classes = Customer2Application.class) class CoreFunctionXYTestWithCustomer2 extends AbstractSpringBootTest 好的,那如果你不依赖 Spring 注解,而是手动创建 ApplicationContext 进行测试呢?然后你可以事先阅读某种配置文件,并确定使用哪种配置类。 是的,这样的东西会很完美,但我在谷歌上找不到任何信息如何做到这一点 我编辑了我的答案,以展示如何欺骗 Spring Boot 让您通过系统属性或配置文件选择 @SpringBootApplication 类。【参考方案2】:

你检查了吗? @SpringBootTest(classes = Customer1Application.class, Customer2Application.class)

【讨论】:

如果我这样做,Spring 会尝试同时启动两个应用程序。这会导致路由映射冲突和其他一些问题。我需要一种可以清楚地将两个应用分开的方法 嗯,也许这是一个解决方法,但如果您需要快速手动自定义测试,您可以:使用@Profile("testprofile") 创建测试配置类。之后只需使用 @AciveProfiles("testprofile") 运行测试以仅从此配置文件加载 bean?

以上是关于如何为不同的应用程序运行相同的 SpringBootTests的主要内容,如果未能解决你的问题,请参考以下文章

如何为具有不同图形和媒体资产的不同发送方应用程序实现相同的自定义接收方应用程序?

如何为 SQL Server 和 SQL Server Compact 编写相同的 ado.net 代码?

如何为不同的客户端在应用商店中管理相同iOS应用的不同版本

如何为不同的类声明相同的对象名称?

Xcode iOS - 使用相同资源的多个测试失败 - 如何为多个测试使用 1 个资源?

如何为不同环境的 SwiftUI App 生命周期应用程序运行 UI 测试?