无法在Spring Boot中为每种测试方法初始化DB

时间:2019-07-01 11:37:37

标签: java spring spring-boot h2 spring-test

我正在尝试为Spring Boot设置一个集成测试方案,在该方案中,将为每个测试方法创建并使用自定义sql代码初始化一个新的H2数据库。

从文档中我了解到,我要做的就是添加

@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)

参加我的测试班。

我从日志中看到,这确实启动了多个应用程序上下文,而不是一个。

但是,这似乎表明,在运行任何测试之前已初始化此上下文,并且实际上同时将其存在于JVM中。但是我认为他们共享一个H2实例。第一次执行sql init脚本就可以了,但是我遇到了Table already exists错误,因为它试图创建已经存在的表。

如何确保测试(包括弹簧应用上下文和H2 DB)已完全序列化?

application.properties

server.port=8001

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.show-sql=true
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=none
spring.datasource.schema=classpath*:h2/ddl/infop-schemas.sql, \
  classpath*:h2/ddl/infop-tables-fahrplan.sql, \
  classpath*:h2/ddl/infop-tables-import.sql, \
  classpath*:h2/ddl/infop-tables-stammdaten.sql, \
  classpath*:h2/ddl/infop-tables-statistik.sql, \
  classpath*:h2/ddl/infop-tables-system.sql, \
  classpath*:h2/ddl/infop-tables-utility.sql, \
  classpath*:h2/ddl/infop-sequences.sql, \
  classpath*:h2/ddl/infop-views.sql \
  classpath*:h2/dll/infop-constraints-system.sql \
  classpath*:h2/dll/infop-constraints-stammdaten.sql \
  classpath*:h2/dll/infop-constraints-statistik.sql \
  classpath*:h2/dll/infop-constraints-import.sql \
  classpath*:h2/dll/infop-constraints-fahrplan.sql

测试类:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {TestApplicationDao.class})
@ActiveProfiles("test")
@Transactional
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class ProtokollIntegrationTest {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProtokollIntegrationTest.class);

    @Test
    public void thatMaxLaufnummerIsFound() {
        LOGGER.debug("thatMaxLaufnummerIsFound()");
        Optional<Protokoll> maxProtokollOpt = protokollRepository.findFirstByAuftragSchrittOrderByLaufnummerDesc(auftragSchritt);

        assertTrue(maxProtokollOpt.isPresent());
        assertEquals(new Integer(9), maxProtokollOpt.get().getLaufnummer());
    }

    @Test
    public void thatNoLaufnummerIsFound() {
        LOGGER.debug("thatNoLaufnummerIsFound()");
        AuftragSchritt as = new AuftragSchritt();
        as.setStatusCode(code);
        auftragSchrittRepository.save(as);

        Optional<Protokoll> maxProtokollOpt = protokollRepository.findFirstByAuftragSchrittOrderByLaufnummerDesc(as);

        assertFalse(maxProtokollOpt.isPresent());
    }

    @Test
    public void thatFindByAuftragSchrittWorksFine() {
        LOGGER.debug("thatFindByAuftragSchrittWorksFine()");
        List<Protokoll> protokollList = protokollRepository.findByAuftragSchritt(auftragSchritt);

        assertNotNull(protokollList);
        assertEquals(10, protokollList.size());
    }

}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.compay.my-prj</groupId>
    <artifactId>my-prj-dao</artifactId>
    <version>0.2.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
        <timestamp>${maven.build.timestamp}</timestamp>
        <junit.jupiter.version>5.4.2</junit.jupiter.version>
        <junit.platform.launcher.version>1.4.2</junit.platform.launcher.version>
        <my-prj.version>8.25.0</my-prj.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
        <dependency>
            <groupId>com.compay.my-prj</groupId>
            <artifactId>my-prj-common-entity</artifactId>
            <version>${my-prj.version}</version>
            <classifier>hibernate</classifier>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <!-- wir werden junit5 verwenden (unten) -->
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.compay.my-prj</groupId>
            <artifactId>my-prj-dao-test</artifactId>
            <version>0.5.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.compay.my-prj</groupId>
            <artifactId>my-prj-common-entity-test</artifactId>
            <version>${my-prj.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>${junit.platform.launcher.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- für junit5 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
        </plugins>
    </build>
</project>

日志输出,请参见https://1drv.ms/t/s!AnJdkNZlKN5ygVi72qB6wL1KOcpZ (很抱歉,SO太大了

2 个答案:

答案 0 :(得分:0)

毕竟这是缺少的依赖项!

我没有

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>

这会导致自动配置发疯,并进行诸如以错误的顺序初始化应用程序上下文之类的事情以及其他奇怪的事情。更糟糕的是,它根本不会发出任何错误或警告消息。

因此,学习是:

如果您的代码中包含@DirtiesContext,则必须将spring-boot-devtools添加到您的附属项中。

答案 1 :(得分:-1)

在将spring.jpa.hibernate.ddl-auto设置为create-drop并将DirtiesContext设置为BEFORE_EACH_TEST_METHOD的普通JPA / Hibernate场景中,它将作为jpa / hibernate尝试删除所有表,然后在每个测试用例执行后再次创建所有表。由hibernate处理的创建/删除场景(在您的情况下不会发生)

但是根据您的设置,即DirtiesContext = BEFORE_EACH_TEST_METHODspring.datasource.schema = <multiple-sql-files>,表是由您的脚本创建的,但不会被删除。因此,您会遇到Table already exists错误。

我建议您在开始时再添加一个SQL文件 ,该文件由查询删除所有创建的表/视图(如果存在)。它肯定会解决您的问题。