Go语言:如何使用testcontainers构建数据访问层的集成测试?

数据库 其他数据库
即使SQL语句在数据库客户端中运行完美,放入程序代码中也不能保证正常工作。使用真实数据库进行测试是确认组件正常运行的唯一方法。

如何确保数据访问层中的SQL语句编写正确?即使在数据库客户端中手动测试通过的SQL语句,放到程序代码中也不能保证一定能正常工作。

问题示例

让我们看一个查询tier=2的客户记录的SQL语句示例:

SELECT id, name, tier, created_at, updated_at
FROM customer
WHERE tier = 2

然而,当这条SQL语句被放入程序代码中时可能会出现问题:

// GO
// connect to database
db, err := sql.Open("mysql", <<database connection string>>)
// execute query
rows, err := db.Query("SELECT id, name, tier," + "created_at, updated_at"+"FROM customer WHERE tier=?", tier)

你能发现问题所在吗?是的,在update_at前的换行处缺少了一个空格。这是在将SQL语句放入程序代码时常见的粗心错误。肉眼检查可能不容易发现这个问题,而合适的自动化测试才是确保程序代码按预期工作的可靠方式。

使用容器进行测试

启动真实数据库进行测试是最佳方法。得益于Docker容器的普及,自动化测试可以在容器中启动数据库进行测试,测试完成后直接销毁。

在Java中,使用库方法调用和JUnit可以轻松实现与数据库的集成测试。那么在GO中是否也可以构建相同的自动化测试呢?

好消息是testcontainers库也支持Go。本文将深入探讨如何使用Go构建集成测试。

数据访问层

为了实现关注点分离和便于维护,将SQL语句混入业务逻辑通常不是一个好主意。最佳实践是将它们封装在一个称为数据访问对象(DAO)的独立组件中,该组件充当业务逻辑和数据库之间的适配器。

使用MySQL测试容器

首先让我们看看如何启动测试容器的基本操作。

需要导入testcontainers库的以下两个包:

import (
    "github.com/testcontainers/testcontainers-go"
    "github.com/testcontainers/testcontainers-go/modules/mysql"
)

使用mysql.Run()并传入以下参数来启动MySQL容器:

  • MySQL镜像版本
  • 数据库名称
  • 用户名和密码
  • 初始数据库脚本
ctx := context.Background()
mysqlContainer, err := mysql.Run(ctx,
    "mysql:8.0.36",
    mysql.WithDatabase("example"),
    mysql.WithUsername("appuser"),
    mysql.WithPassword("passme"),
    mysql.WithScripts(filepath.Join("testdata", "schema.sql")),
)
if err != nil {
    log.Panicf("failed to start container: %s\n", err)
}

连接MySQL容器

要连接MySQL数据库,需要导入Go的标准库database/sql和MySQL驱动。为避免与testcontainer库的MySQL模块名称冲突,给驱动包添加下划线别名:

import (
    _ "github.com/go-sql-driver/mysql"
    "database/sql"
)

与Java类似,Go中的数据库连接也是通过连接字符串实现。testcontainers库提供了一个便捷函数mysqlContainer.ConnectionString(),它可以生成格式正确的连接字符串。

测试套件实现

首先,定义一个包含客户DAO、MySQL容器和数据库连接引用的测试套件结构体。suite.Suite提供了测试框架的元素,如用于管理测试状态和支持测试日志的testing.T。

type CustomerDaoTestSuite struct {
    suite.Suite
    dao            *dao.CustomerDao
    mysqlContainer *mysql.MySQLContainer
    db             *sql.DB
}

生命周期函数

Testify框架提供了以下接口来实现测试生命周期:

  • SetupSuite() - 在所有测试场景执行前调用一次(相当于JUnit中的@BeforeAll)
  • SetupTest() - 每个测试场景前的设置函数(相当于JUnit中的@BeforeEach)
  • TearDownTest() - 每个测试场景完成后的清理函数(相当于JUnit中的@AfterEach)
  • TearDownSuite() - 在所有测试场景结束后调用一次(相当于JUnit中的@AfterAll)

最终思考

数据访问层的集成测试至关重要。即使SQL语句在数据库客户端中运行完美,放入程序代码中也不能保证正常工作。使用真实数据库进行测试是确认组件正常运行的唯一方法。

借助testcontainers库和Testify框架,集成测试可以自动启动容器中的数据库,并在完整的测试生命周期中将DAO连接到数据库进行测试,就像Java中的JUnit一样。该库对开发人员友好,只需几个函数调用就能轻松完成测试设置。

责任编辑:武晓燕 来源: 源自开发者
相关推荐

2023-07-27 08:16:51

数据访问层项目

2011-05-10 16:44:43

数据访问层

2011-05-05 14:33:34

数据访问层

2021-11-29 22:59:34

Go Dockertest集成

2023-12-26 00:58:53

Web应用Go语言

2009-08-04 10:17:55

ASP.NET SqlASP.NET数据访问

2021-04-16 20:43:18

Go区块链编程

2013-03-12 09:50:45

GoRESTful Web

2023-11-09 16:12:06

大数据大数据堆栈

2014-04-09 09:32:24

Go并发

2021-02-03 15:10:38

GoKubernetesLinux

2012-11-20 10:20:57

Go

2011-05-07 12:56:39

数据访问

2011-03-29 09:15:28

通用数据访问层

2024-08-05 10:26:42

Go语言架构

2020-08-05 12:27:18

Go语言码农

2012-08-13 09:15:54

Go开发语言编程语言

2014-10-15 11:01:02

Web应用测试应用

2024-01-31 08:01:36

Go延迟队列语言

2024-08-02 08:43:44

点赞
收藏

51CTO技术栈公众号