我应该如何在 SpringBoot 库(不是应用程序)上执行集成测试

问题描述 投票:0回答:1

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

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

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

单元测试工作正常。

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

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

我们在测试层次结构中有一个引导配置,IT 在通过 IDE 运行时必须使用该配置,但是在运行 Maven 构建时,似乎无法找到启动应用程序(可以理解,因为它位于测试包中)树)。 我们拥有的启动文件只不过是一个运行库、运行 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;
...
}

第二个让我研究@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);
        }
}

这似乎有效。谢谢你的提示。

java spring spring-boot maven
1个回答
3
投票

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

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

除此之外,它还执行 Spring Boot 应用程序在启动期间执行的许多其他操作:加载遵循 Spring Boot 应用程序约定的配置(application.properties/yaml)、加载自动配置(

spring.factories
中的内容)等等。

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

到目前为止一切顺利,但你说你并没有真正拥有 Spring Boot 应用程序。所以我看到三种方法:

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

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

  3. 根本不要使用

    @SpringBootTest
    注释,而更喜欢“通常”
    @ContextConfiguration
    - 是的,您不会拥有 Spring Boot 的功能,但正如我上面所说,您可能不需要它。此外,这些测试会更快,特别是如果您提供许多“@Configuration”类并且在测试期间仅加载库的“相关”部分。 例如,如果您测试 DAO,则加载 Web 相关内容是没有意义的。

© www.soinside.com 2019 - 2024. All rights reserved.