前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Go 语言结合 Docker 进行集成测试

Go 语言结合 Docker 进行集成测试

原创
作者头像
陈明勇
发布2024-10-25 18:45:56
发布2024-10-25 18:45:56
1660
举报
文章被收录于专栏:Go 技术Go 技术Go技术干货

前言

Go 语言开发中,结合 Docker 进行集成测试是一种高效的方法,它能够在隔离的容器环境中运行服务,确保测试结果的一致性。这种方式特别适用于需要依赖外部服务(如数据库、缓存系统、外部 API 等)的测试场景。结合 Docker 进行集成测试的方式主要有两种:通过 docker-compose 配置测试环境,以及 使用 dockertest 库管理容器。本文将重点介绍如何在 Go 语言中使用 dockertest 进行集成测试。

准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。

dockertest

dockertest 是一个 Go 语言的库,用于在测试过程中轻松管理和控制 Docker 容器。它能快速启动、配置和销毁容器,使得开发者可以在集成测试中隔离外部服务(例如数据库、缓存系统等),确保测试的一致性和可靠性。相较于 docker-composedockertest 更加轻量级且灵活,适合在测试代码中直接控制容器生命周期。

安装 dockertest

在项目中添加 dockertest 库。在项目根目录的终端中运行以下命令:

代码语言:bash
复制
go get github.com/ory/dockertest/v3

创建测试文件并初始化 dockertest 资源池并启动 MySQL 容器

在项目中创建一个测试文件,例如 mysql_test.go,然后在 TestMain 函数中使用 dockertest 启动 MySQL 容器,并在所有测试用例运行之前设置好数据库连接。

代码语言:go
复制
var db *sql.DB // 全局数据库连接

func TestMain(m *testing.M) {
	// 创建 dockertest 资源池
	pool, err := dockertest.NewPool("")
	if err != nil {
		log.Fatalf("Could not connect to Docker: %s", err)
	}

	// 启动 MySQL 容器并设置环境变量
	resource, err := pool.Run("mysql", "8.0", []string{
		"MYSQL_ROOT_PASSWORD=secret",
		"MYSQL_DATABASE=testdb",
		"MYSQL_USER=testuser",
		"MYSQL_PASSWORD=testpass",
	})
	if err != nil {
		log.Fatalf("Could not start resource: %s", err)
	}

	// 确保测试结束时删除容器
	defer func() {
		if err := pool.Purge(resource); err != nil {
			log.Fatalf("Could not purge resource: %s", err)
		}
	}()

	// 重试连接 MySQL,直到服务准备就绪
	if err := pool.Retry(func() error {
		var err error
		db, err = sql.Open("mysql", "testuser:testpass@tcp(localhost:"+resource.GetPort("3306/tcp")+")/testdb")
		if err != nil {
			return err
		}
		return db.Ping()
	}); err != nil {
		log.Fatalf("Could not connect to database: %s", err)
	}

	// 运行测试
	code := m.Run()

	// 测试结束时关闭数据库连接
	if err := db.Close(); err != nil {
		log.Fatalf("Could not close database connection: %s", err)
	}

	os.Exit(code)
}

编写测试用例

现在,写一个简单的测试用例来验证数据库的基本操作。例如,可以测试创建一张表、插入数据,并查询数据。

代码语言:go
复制
func TestMySQLInsert(t *testing.T) {
	// 创建测试表
	_, err := db.Exec("CREATE TABLE IF NOT EXISTS items (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255))")
	if err != nil {
		t.Fatalf("Could not create table: %s", err)
	}

	// 插入一条测试数据
	_, err = db.Exec("INSERT INTO items (name) VALUES (?)", "test item")
	if err != nil {
		t.Fatalf("Could not insert item: %s", err)
	}

	// 查询并验证数据
	var name string
	err = db.QueryRow("SELECT name FROM items WHERE name=?", "test item").Scan(&name)
	if err != nil {
		t.Fatalf("Could not query item: %s", err)
	}

	if name != "test item" {
		t.Errorf("Expected 'test item', got '%s'", name)
	}
}

完整代码

代码语言:go
复制
package stringx

import (
	"database/sql"
	"log"
	"os"
	"testing"

	_ "github.com/go-sql-driver/mysql" // MySQL driver
	"github.com/ory/dockertest/v3"
)

var db *sql.DB // 全局数据库连接

func TestMain(m *testing.M) {
	// 创建 dockertest 资源池
	pool, err := dockertest.NewPool("")
	if err != nil {
		log.Fatalf("Could not connect to Docker: %s", err)
	}

	// 启动 MySQL 容器并设置环境变量
	resource, err := pool.Run("mysql", "8.0", []string{
		"MYSQL_ROOT_PASSWORD=secret",
		"MYSQL_DATABASE=testdb",
		"MYSQL_USER=testuser",
		"MYSQL_PASSWORD=testpass",
	})
	if err != nil {
		log.Fatalf("Could not start resource: %s", err)
	}

	// 确保测试结束时删除容器
	defer func() {
		if err := pool.Purge(resource); err != nil {
			log.Fatalf("Could not purge resource: %s", err)
		}
	}()

	// 重试连接 MySQL,直到服务准备就绪
	if err := pool.Retry(func() error {
		var err error
		db, err = sql.Open("mysql", "testuser:testpass@tcp(localhost:"+resource.GetPort("3306/tcp")+")/testdb")
		if err != nil {
			return err
		}
		return db.Ping()
	}); err != nil {
		log.Fatalf("Could not connect to database: %s", err)
	}

	// 运行测试
	code := m.Run()

	// 测试结束时关闭数据库连接
	if err := db.Close(); err != nil {
		log.Fatalf("Could not close database connection: %s", err)
	}

	os.Exit(code)
}

func TestMySQLInsert(t *testing.T) {
	// 创建测试表
	_, err := db.Exec("CREATE TABLE IF NOT EXISTS items (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255))")
	if err != nil {
		t.Fatalf("Could not create table: %s", err)
	}

	// 插入一条测试数据
	_, err = db.Exec("INSERT INTO items (name) VALUES (?)", "test item")
	if err != nil {
		t.Fatalf("Could not insert item: %s", err)
	}

	// 查询并验证数据
	var name string
	err = db.QueryRow("SELECT name FROM items WHERE name=?", "test item").Scan(&name)
	if err != nil {
		t.Fatalf("Could not query item: %s", err)
	}

	if name != "test item" {
		t.Errorf("Expected 'test item', got '%s'", name)
	}
}

运行测试

在终端中运行测试命令,go test 会执行集成测试,启动 MySQL 容器,运行测试代码,然后销毁容器。

代码语言:bash
复制
go test -v

小结

通过 dockertest 启动 MySQL 容器,我们能够在集成测试中方便地使用隔离的 MySQL 实例。这种方法适用于数据库操作的测试,让测试结果更具一致性,同时降低了环境依赖。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • dockertest
    • 安装 dockertest
    • 创建测试文件并初始化 dockertest 资源池并启动 MySQL 容器
    • 编写测试用例
    • 完整代码
    • 运行测试
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档