golang数据库测试辅助工具插件库testfixtures的使用

Golang数据库测试辅助工具插件库testfixtures的使用

testfixtures是一个用于简化Golang数据库应用功能测试的工具库,它模仿了Ruby on Rails的测试数据库方式。

警告

这个包会在加载fixtures前清空数据库数据!它应该只用于测试数据库。请仔细确认你是在正确的数据库上运行它。

安装

首先导入包:

import (
    "github.com/go-testfixtures/testfixtures/v3"
)

使用方式

创建fixture文件

创建一个文件夹存放fixture文件,每个文件对应一个表,命名为<表名>.yml

myapp/
  myapp.go
  myapp_test.go
  ...
  fixtures/
    posts.yml
    comments.yml
    tags.yml
    posts_tags.yml
    ...

fixture文件内容示例:

# comments.yml
- id: 1
  post_id: 1
  content: A comment...
  author_name: John Doe
  author_email: john@doe.com
  created_at: 2020-12-31 23:59:59
  updated_at: 2020-12-31 23:59:59

- id: 2
  post_id: 2
  content: Another comment...
  author_name: John Doe
  author_email: john@doe.com
  created_at: 2020-12-31 23:59:59
  updated_at: 2020-12-31 23:59:59

测试代码示例

package myapp

import (
    "database/sql"
    "testing"

    _ "github.com/lib/pq"
    "github.com/go-testfixtures/testfixtures/v3"
)

var (
    db *sql.DB
    fixtures *testfixtures.Loader
)

func TestMain(m *testing.M) {
    var err error

    // 打开测试数据库连接
    // 不要在正式数据库中使用fixtures!
    // 现有数据会被删除
    db, err = sql.Open("postgres", "dbname=myapp_test")
    if err != nil {
        ...
    }

    fixtures, err = testfixtures.New(
        testfixtures.Database(db), // 数据库连接
        testfixtures.Dialect("postgres"), // 支持:"postgresql", "timescaledb", "mysql", "mariadb", "sqlite"和"sqlserver"
        testfixtures.Directory("testdata/fixtures"), // 包含YAML文件的目录
    )
    if err != nil {
        ...
    }

    os.Exit(m.Run())
}

func prepareTestDatabase() {
    if err := fixtures.Load(); err != nil {
        ...
    }
}

func TestX(t *testing.T) {
    prepareTestDatabase()
    // 你的测试代码...
}

func TestY(t *testing.T) {
    prepareTestDatabase()
    // 你的测试代码...
}

func TestZ(t *testing.T) {
    prepareTestDatabase()
    // 你的测试代码...
}

其他加载方式

可以使用Files选项指定要加载的文件:

fixtures, err := testfixtures.New(
    testfixtures.Database(db),
    testfixtures.Dialect("postgres"),
    testfixtures.Files(
        "fixtures/orders.yml",
        "fixtures/customers.yml",
    ),
)

或者使用Paths选项指定路径:

fixtures, err := testfixtures.New(
    testfixtures.Database(db),
    testfixtures.Dialect("postgres"),
    testfixtures.Paths(
        "fixtures/orders.yml",
        "fixtures/customers.yml",
        "common_fixtures/users"
    ),
)

单个文件包含多个表

使用FilesMultiTables选项可以在单个文件中定义多个表的数据:

fixtures, err := testfixtures.New(
    testfixtures.Database(db),
    testfixtures.Dialect("postgres"),
    testfixtures.FilesMultiTables(
        "fixtures/test_case1.yml",
        "fixtures/test_case2.yml",
        "fixtures/posts_comments.yml",
    ),
)

多表文件示例:

# test_case1.yml
posts:
  - id: 1
    post_id: 1
    content: A comment...
    author_name: John Doe
    author_email: john@doe.com
    created_at: 2020-12-31 23:59:59
    updated_at: 2020-12-31 23:59:59

comments:
  - id: 1
    post_id: 1
    content: Post 1 comment 1
    author_name: John Doe
    author_email: john@doe.com
    created_at: 2016-01-01 12:30:12
    updated_at: 2016-01-01 12:30:12

高级功能

安全检查和跳过

testfixtures.New(
    ...
    testfixtures.DangerousSkipTestDatabaseCheck(),
)

禁用清理

testfixtures.New(
    ...
    testfixtures.DangerousSkipCleanupFixtureTables(),
)

序列重置

testfixtures.New(
    ...
    testfixtures.ResetSequencesTo(10000),
)

模板支持

testfixtures.New(
    ...
    testfixtures.Template(),
    testfixtures.TemplateFuncs(...),
    testfixtures.TemplateDelims("{{", "}}"),
    testfixtures.TemplateOptions("missingkey=zero"),
    testfixtures.TemplateData(...),
)

从现有数据库生成fixtures

dumper, err := testfixtures.NewDumper(
    testfixtures.DumpDatabase(db),
    testfixtures.DumpDialect("postgres"), // 或你选择的数据库
    testfixtures.DumpDirectory("tmp/fixtures"),
    testfixtures.DumpTables( // 可选,不指定则导出所有表
      "posts",
      "comments",
      "tags",
    ),
)
if err != nil {
    ...
}
if err := dumper.Dump(); err != nil {
    ...
}

注意事项

并行测试

这个库还不支持并行测试!并行测试可能导致数据库中出现随机数据,这可能会导致测试随机/间歇性失败。

替代方案

如果你认为使用fixtures不是一个好主意,可以尝试以下替代方案:

  • factory-go: Go的工厂模式实现
  • fixtory: 基于go generate的类型安全测试fixture工厂
  • go-txdb: 为每个功能测试使用单一数据库事务
  • go-sqlmock: sql.DB接口的mock实现
  • dbcleaner: 测试数据库清理工具

更多关于golang数据库测试辅助工具插件库testfixtures的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang数据库测试辅助工具插件库testfixtures的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 数据库测试辅助工具 testfixtures 使用指南

testfixtures 是一个用于 Golang 数据库测试的辅助工具库,它可以帮助你在测试前将数据库置于已知状态,确保测试的一致性。

安装

go get github.com/go-testfixtures/testfixtures/v3

基本使用

1. 准备工作

首先,准备你的测试数据文件。testfixtures 支持 YAML 或 JSON 格式的文件,通常存放在 testdata/fixtures 目录下。

示例 YAML 文件 (users.yml):

users:
  - id: 1
    name: "John Doe"
    email: "john@example.com"
    created_at: "2020-01-01 00:00:00"
  
  - id: 2
    name: "Jane Smith"
    email: "jane@example.com"
    created_at: "2020-01-02 00:00:00"

2. 初始化 testfixtures

package main_test

import (
	"database/sql"
	"log"
	"path/filepath"
	"testing"

	_ "github.com/go-sql-driver/mysql"
	"github.com/go-testfixtures/testfixtures/v3"
)

var (
	db       *sql.DB
	fixtures *testfixtures.Loader
)

func TestMain(m *testing.M) {
	var err error
	
	// 1. 初始化数据库连接
	db, err = sql.Open("mysql", "user:password@tcp(localhost:3306)/testdb?parseTime=true")
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	
	// 2. 准备 fixtures 加载器
	fixtures, err = testfixtures.New(
		testfixtures.Database(db),        // 数据库连接
		testfixtures.Dialect("mysql"),    // 数据库方言
		testfixtures.Directory(filepath.Join("testdata", "fixtures")), // fixtures 目录
	if err != nil {
		log.Fatalf("Error creating fixtures: %v", err)
	}
	
	// 运行测试
	m.Run()
}

3. 在测试中使用

func TestUserCount(t *testing.T) {
	// 加载 fixtures
	if err := fixtures.Load(); err != nil {
		t.Fatalf("Error loading fixtures: %v", err)
	}
	
	// 执行测试查询
	var count int
	err := db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count)
	if err != nil {
		t.Fatalf("Error querying user count: %v", err)
	}
	
	// 验证结果
	if count != 2 {
		t.Errorf("Expected 2 users, got %d", count)
	}
}

高级功能

1. 跳过重置表

fixtures, err = testfixtures.New(
	testfixtures.Database(db),
	testfixtures.Dialect("mysql"),
	testfixtures.Directory("testdata/fixtures"),
	testfixtures.SkipResetTables(), // 跳过表重置
)

2. 使用模板变量

fixtures 文件支持模板变量:

users:
  - id: 1
    name: "{{.UserName}}"
    email: "{{.UserEmail}}"

在代码中设置变量:

fixtures, err = testfixtures.New(
	// ...其他选项...
	testfixtures.Template(),
	testfixtures.TemplateData(map[string]interface{}{
		"UserName":  "Test User",
		"UserEmail": "test@example.com",
	}),
)

3. 使用自定义函数

func myCustomFunc() string {
	return "custom_value"
}

fixtures, err = testfixtures.New(
	// ...其他选项...
	testfixtures.Template(),
	testfixtures.TemplateFuncs(template.FuncMap{
		"myCustomFunc": myCustomFunc,
	}),
)

然后在 YAML 中使用:

users:
  - id: 1
    custom_field: "{{myCustomFunc}}"

4. 只加载特定文件

fixtures, err = testfixtures.New(
	// ...其他选项...
	testfixtures.Files("users.yml", "products.yml"),
)

支持的数据库

testfixtures 支持多种数据库:

  • PostgreSQL
  • MySQL
  • SQLite
  • Microsoft SQL Server
  • Oracle

注意事项

  1. 确保测试数据库与生产数据库分开
  2. 测试完成后可以考虑回滚事务或清理数据库
  3. 对于大型测试数据集,考虑使用事务来加速测试

testfixtures 是一个强大的工具,可以显著简化数据库测试的设置工作,确保每次测试都在一致的数据状态下运行。

回到顶部