【问题标题】:How should I perform integration testing on a SpringBoot library, that isn't an application我应该如何在不是应用程序的 SpringBoot 库上执行集成测试
【发布时间】:2020-11-24 17:00:18
【问题描述】:

首先,免责声明,我对我将要询问的架构并不完全满意!

我们有一个基于 Spring 的项目,该项目将库生成为 jar。该库包含您可能期望的所有常用控制器/服务/jpa(存储库)层,但没有启动应用程序来启动它。

我们组织内的各种项目的想法可以导入 jar 并立即添加通用 (HTTP) API。

单元测试工作正常。

*IT.java 测试是另一回事。 IDE 与它们运行正常并通过的 test/java/ 层次结构隔离运行。

但是,当通过 maven 作为构建的一部分运行时,它们会失败。 [错误] ControllerIT » IllegalState 找不到 @SpringBootConfiguration...

我们在测试层次结构中有一个引导配置,IT 在通过 IDE 运行时必须使用它,但是在运行 maven 构建时,似乎找不到启动应用程序(可以理解,因为它在测试包树)。 我们所拥有的引导文件只是用来运行 lib 和运行 IT 的测试工具。

我们在 Maven 测试范围内有 h2,但最终库中不需要它(由宿主应用程序提供数据源/连接等)。

要求

  • 在应用程序中启动 API 库以进行测试
  • 在 Maven 构建过程中运行测试
  • H2 不应出现在最终罐中

运行 mvn install 时的症状 [错误] ControllerIT » IllegalState 找不到 @SpringBootConfiguration...

大概需要在 pom 中的某个地方进行一些配置?已经在 Springboot maven 插件配置中使用 package.Boot。 也许只需要弄清楚魔术配置将其指向 src/test/... Boot.class 而不是 src/main/...Boot.class

问题

spring 是否有一种“正确”的方式来实现我们想要的(我会选择微服务,但不是一个选项,因为......原因)?

当我们不想在产品 jar 中包含可引导类(或 H2 库)时,我们应该如何针对 H2 驱动的 SpringBoot 应用程序实施 IT?

我们是否应该为 IT 创建一个单独的 Maven 模块(依赖于库模块)?

Maven pom 的缩写:

   <properties>
      <version.spring-boot>2.1.13.RELEASE</version.spring-boot>
   </properties>
   <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${version.spring-boot}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                  <groupId>org.junit.vintage</groupId>
                  <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
            </exclusions>
           <dependency>
              <groupId>com.h2database</groupId>
              <artifactId>h2</artifactId>
              <scope>test</scope>
           </dependency>
           <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>2.28.2</version>
            <scope>test</scope>
           </dependency>
           <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <version>2.28.2</version>
            <scope>test</scope>
           </dependency>
           <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.4.0</version>
            <type>pom</type>
            <scope>test</scope>
           </dependency>
           <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <scope>test</scope>
           </dependency>
           <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
           </dependency>
        
        <!-- other dependencies excluded for brevity -->
     </dependencies>
     <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${version.spring-boot}</version>
                <configuration>
                    <!-- file lives in test hierarchy -->
                    <mainClass>org.my.packages.test.Boot</mainClass>
                </configuration>
            </plugin>
      
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
              <configuration>
                <skip>true</skip><!-- Skipping unit tests while trying to sort ITs -->
              </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.0.0-M5</version>
                <configuration>
                  <failIfNoTests>true</failIfNoTests>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </execution>
             </plugin>
        </plugins>
</build>

Spring Boot 配置:

@SpringBootApplication()
public class Boot extends SpringBootServletInitializer
{
    public static void main(String[] args)
    {
        SpringApplication.run(Boot.class, args);
    }
}

IT 配置:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ControllerIT
{

    @Autowired
    private TestRestTemplate restTemplate;
...
}

第 2 位引导我查看 @SpringBootTest 的参数。 最后我...

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    classes = ITConfig.class)

ITConfig 在哪里:

@SpringBootApplication()
public class ITConfig extends SpringBootServletInitializer
{
    public static void main(String[] args)
        {
            SpringApplication.run(org.lhasalimited.libraries.ITConfig.class, args);
        }
}

这似乎奏效了。感谢您的提示。

【问题讨论】:

    标签: spring spring-boot maven


    【解决方案1】:

    让我提出一种解决此问题的方法,可能还有其他方法:

    @SpringBootTest 注释旨在模拟完整的 Spring Boot 应用程序的启动。 它扫描包直到找到@SpringBootConfiguration 注释(这个注释已经放在@SpringBootApplication 上),这样它就知道应该扫描包到找到主类的包(到找到所有的豆子)。

    除此之外,它还做了 Spring Boot 应用程序在启动期间所做的许多其他事情:加载配置 (application.properties/yaml) 遵守 Spring Boot 应用程序的约定,加载自动配置(spring.factories 内的东西)等等第四次。

    最重要的是,您将在测试中加载一个成熟的 Spring Boot 应用程序(通常是微服务)。

    到目前为止一切顺利,但你说你并没有真正的 spring boot 应用程序。所以我看到了三种方式:

    1. src/test/java/whatever-package-close-to-root 文件夹中引入一个带有@SpringBootConfiguration 的人工类(注意,它在“测试”中,而不是在src/main 中)

    2. 使用带有“配置”参数的@SpringBootTest。这意味着SpringBootTest 不会使用所有这种上下扫描过程,而是指示它使用具体的上下文配置。

    3. 根本不要使用@SpringBootTest 注释,而更喜欢“通常的”@ContextConfiguration - 是的,你不会拥有弹簧靴的力量,但正如我上面所说的,你可能不需要它。此外,这些测试会更快,特别是如果您将提供许多“@Configuration”类并且在测试期间将仅加载库的“相关”部分。 例如,如果您测试 DAO,则加载与 Web 相关的内容毫无意义。

    【讨论】:

    • hmm 格式在这里不起作用...将添加到问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    相关资源
    最近更新 更多