在Spring Boot测试中使用Testcontainer进行数据库集成测试

本文详细介绍了如何在Spring Boot测试中利用Testcontainers进行数据库集成测试,包括基于JDBC、JPA和Spring Data JPA的测试存储库。讨论了如何设置数据库容器、配置JDBC和JPA连接,并展示了如何重用数据库实例以提高测试效率。同时,还给出了测试整个Web应用程序的方法。

在此博客文章中,我想演示如何在Spring Boot测试中集成Testcontainer以便与数据库一起运行集成测试。 我没有使用Testcontainers的Spring Boot模块。 如何与他们合作,我将在另一篇博客文章中进行介绍。 所有示例都可以在GitHub找到

为什么要使用测试容器?

Testcontainers是一个库,可帮助在基于Docker容器的集成测试中集成数据库等基础架构组件。 它有助于避免编写集成测试。 这些是根据另一个系统的正确性通过或失败的测试。 使用Testcontainer,我可以控制这些从属系统。

域介绍

进一步的示例展示了不同的方法,该方法如何通过数据库中不同的存储库实现来保存一些英雄对象,以及相应的测试看起来如何。

package com.github.sparsick.testcontainerspringboot.hero.universum;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.util.Objects;
 
public class Hero {
    private Long id;
    private String name;
    private String city;
    private ComicUniversum universum;
 
    public Hero(String name, String city, ComicUniversum universum) {
        this.name = name;
        this.city = city;
        this.universum = universum;
    }
 
    public String getName() {
        return name;
    }
 
    public String getCity() {
        return city;
    }
 
    public ComicUniversum getUniversum() {
        return universum;
    }
}

所有其他存储库都是Spring Boot Web应用程序的一部分。 因此,在本博客文章的结尾,我将演示如何为整个Web应用程序(包括数据库)编写测试。 让我们从一个简单的示例开始,该示例基于JDBC。

基于JDBC测试存储库

假设我们有以下基于JDBC的存储库实现。 我们有两种方法,一种是将英雄添加到数据库中,另一种是从数据库中获取所有英雄。

package com.github.sparsick.testcontainerspringboot.hero.universum;
 
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
 
import javax.sql.DataSource;
import java.util.Collection;
 
@Repository
public class HeroClassicJDBCRepository {
 
    private final JdbcTemplate jdbcTemplate;
 
    public HeroClassicJDBCRepository(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }
 
    public void addHero(Hero hero) {
        jdbcTemplate.update("insert into hero (city, name, universum) values (?,?,?)",
                hero.getCity(), hero.getName(), hero.getUniversum().name());
 
    }
 
    public Collection
   
     allHeros() {
        return jdbcTemplate.query("select * From hero",
                (resultSet, i) -> new Hero(resultSet.getString("name"),
                                            resultSet.getString("city"),
                                            ComicUniversum.valueOf(resultSet.getString("universum"))));
    }
 
}

   

对于此存储库,我们可以编写普通的JUnit5测试,而无需加载Spring应用程序上下文。 因此,首先,我们必须建立对测试库的依赖关系,在这种情况下为JUnit5和Testcontainers。 作为构建工具,我使用Maven。 这两个测试库都提供了所谓的BOM“物料清单” ,这有助于避免我所使用的依赖项中的版本不匹配。 作为数据库,我想使用MySQL。 因此,除了核心模块testcontainers之外,我还使用了Testcontainers的模块mysql 。 它提供了一个预定义的MySQL容器。 为了简化JUnit5测试代码中专门的容器设置,Testcontainers提供了一个JUnit5模块junit-jupiter

<dependencies>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>testcontainers</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>mysql</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.junit</groupId>
            <artifactId>junit-bom</artifactId>
            <version>${junit.jupiter.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>testcontainers-bom</artifactId>
            <version>${testcontainers.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

现在,我们拥有编写第一个测试的所有内容。

package com.github.sparsick.testcontainerspringboot.hero.universum;
 
import ...
 
@Testcontainers
class HeroClassicJDBCRepositoryIT {
    @Container
    private MySQLContainer database = new MySQLContainer();
 
    private HeroClassicJDBCRepository repositoryUnderTest;
 
    @Test
    void testInteractionWithDatabase() {
        ScriptUtils.runInitScript(new JdbcDatabaseDelegate(database, ""),"ddl.sql");
        repositoryUnderTest = new HeroClassicJDBCRepository(dataSource());
 
        repositoryUnderTest.addHero(new Hero("Batman", "Gotham City", ComicUniversum.DC_COMICS));
 
        Collection<Hero> heroes = repositoryUnderTest.allHeros();
 
        assertThat(heroes).hasSize(1);
    }
 
    @NotNull
    private DataSource dataSource() {
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUrl(database.getJdbcUrl());
        dataSource.setUser(database.getUsername());
        dataSource.setPassword(database.getPassword());
        return dataSource;
    }
}

让我们看看如何为测试准备数据库。 首先,我们使用@Testcontainers注释测试类。 该注释的后面隐藏了Testcontainers提供的JUnit5扩展。 它检查Docker是否安装在计算机上,并在测试期间启动和停止容器。 但是,Testcontainers如何知道应该从哪个容器开始? 在这里,注释@Container帮助。 它标记了应由Testcontainers扩展管理的容器。 在这种情况下,一个MySQLContainer由Testcontainers模块提供mysql 。 此类提供了MySQL Docker容器,并处理诸如设置数据库用户,识别何时可以使用数据库等问题。一旦数据库准备就绪可以使用,就必须设置数据库架构。 测试容器也可以在此处提供支持。 ScriptUtils. runInitScript (new JdbcDatabaseDelegate(database, ""),"ddl.sql");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值