golang实现SQL、NoSQL和结构化文件数据存储测试的插件库dsunit的使用

Golang实现SQL、NoSQL和结构化文件数据存储测试的插件库dsunit的使用

介绍

dsunit是一个用于Go语言的数据存储测试库,属于黑盒测试范畴,主要关注数据存储的初始状态和最终状态。

该框架提供了两种功能:

  1. 设置数据存储的初始状态(可以创建空数据存储或用测试数据集准备数据存储)
  2. 测试最终状态(验证应用程序运行后数据集数据是否匹配预期值)

动机

该库设计目的是为任何平台、语言和云环境下的任何数据存储(SQL、NoSQL、文件日志)提供统一且简单的测试方式。

使用示例

数据设置和验证

1. 使用专用预期数据文件夹

import (
    "testing"
    "github.com/viant/dsunit"
    _ "github.com/go-sql-driver/mysql"
)

func Test_Usecase(t *testing.T) {
    parent := toolbox.CallerDirectory(3)
    if !dsunit.InitFromURL(t, path.Join(parent, "test", "config.yaml")) {
        return
    }
    
    // 业务测试逻辑
    
    expectURL := path.Join(parent, "test/case1/data/expect")
    expectedData := dsunit.NewDatasetResource("db1", expectURL , "", "")
    dsunit.Expect(t, dsunit.NewExpectRequest(dsunit.FullTableDatasetCheckPolicy, expectedData))
}

2. 使用共享预期数据文件夹

func Test_Usecase(t *testing.T) {
    parent := toolbox.CallerDirectory(3)
    if !dsunit.InitFromURL(t, path.Join(parent, "test", "config.yaml")) {
        return
    }
    
    // 业务测试逻辑

    baseDir := path.Join(parent, "test", "data")
    dsunit.ExpectFor(t, "db1", dsunit.FullTableDatasetCheckPolicy, baseDir, "use_case_1")
}

强制在加载数据前清空表

在数据文件中,如果第一个元素是空map,dsunit会在插入提供的数据集前删除表中的所有记录:

[ {},
    {"id":1,"name":"name 1"},
    {"id":2,"name":"name 2"}
]

空数组会移除表中的所有记录:

[]

逆向工程数据设置和验证

registerResponse := service.Register(dsunit.NewRegisterRequest("db1",
        &dsc.Config{
            DriverName: "sqlite3",
            Descriptor: "[url]",
            Parameters: map[string]interface{}{
                "url": filename,
            },
        }))
if registerResponse.Stats != "ok" {
    log.Fatal(registerResponse.Error)
}

response := service.Freeze(&dsunit.FreezeRequest{
        Datastore:"db1",
        DestURL:"/tmp/dn1/expect/users.json",
        SQL:"SELECT * FROM users",
})

验证机制

该库使用assertly作为底层验证机制。

宏是带有参数的表达式,用于扩展原始文本值。格式:<ds:MACRO_NAME [json格式的参数数组]>

内置宏:

名称 参数 描述 示例
sql SQL表达式 返回SQL表达式的值 <ds:sql["SELECT CURRENT_DATE()"]>
seq 序列/表的自增名称 返回序列值 <ds:seq["users"]>

指令

数据准备

@autoincrement@ - 指定自增字段

[
  {"[@autoincrement](/user/autoincrement)@":"id"},
  {"id":1, "username":"Dudi", "active":true, "salary":12400, "comments":"abc","last_access_time": "2016-03-01 03:10:00"},
  {"id":2, "username":"Rudi", "active":true, "salary":12600, "comments":"def","last_access_time": "2016-03-01 05:10:00"}
]

@indexBy@ - 指定主键字段

[
  {"[@indexBy](/user/indexBy)@":["id"]},
  {"id":1, "username":"Dudi", "active":true, "salary":12400, "comments":"abc","last_access_time": "2016-03-01 03:10:00"},
  {"id":2, "username":"Rudi", "active":true, "salary":12600, "comments":"def","last_access_time": "2016-03-01 05:10:00"}
]

数据验证

@fromQuery@ - 指定查询以获取实际数据集与预期数据集进行验证

[
  {"[@fromQuery](/user/fromQuery)@":"SELECT * FROM users where id <= 2 ORDER BY id"},
  {"id":1, "username":"Dudi", "active":true, "salary":12400, "comments":"abc","last_access_time": "2016-03-01 03:10:00"},
  {"id":2, "username":"Rudi", "active":true, "salary":12600, "comments":"def","last_access_time": "2016-03-01 05:10:00"}
]

示例项目

RDBMS

  • Big Query
  • MySQL
  • Oracle
  • Postgres

NoSQL

  • Aerospike
  • MongoDB
  • Cassandra
  • Firebase
  • DynamoDB

许可证

源代码根据Apache License, Version 2提供,详见LICENSE文件。

作者和贡献者

库作者: Adrian Witas
贡献者: Sudhakaran Dharmaraj


更多关于golang实现SQL、NoSQL和结构化文件数据存储测试的插件库dsunit的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现SQL、NoSQL和结构化文件数据存储测试的插件库dsunit的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


dsunit: Go语言数据存储测试插件库

dsunit是一个用于测试SQL、NoSQL和结构化文件数据存储的Go语言插件库,它提供了一套统一的API来准备测试数据、验证存储结果以及清理测试环境。

主要特性

  1. 支持多种数据库类型:MySQL, PostgreSQL, Oracle, SQL Server, SQLite等
  2. 支持NoSQL数据库:MongoDB, DynamoDB等
  3. 支持结构化文件:CSV, JSON, XML等
  4. 提供数据准备和验证功能
  5. 支持测试数据的外部化配置

安装

go get github.com/viant/dsunit

基本使用示例

1. 初始化测试环境

import (
	"github.com/viant/dsunit"
	"testing"
)

func TestMain(m *testing.M) {
	// 初始化测试环境
	dsunit.InitDatastores()
	
	// 运行测试
	m.Run()
	
	// 清理测试环境
	dsunit.CleanupDatastores()
}

2. SQL数据库测试示例

func TestSQLDatabase(t *testing.T) {
	// 注册数据库连接
	err := dsunit.RegisterDatabase("test_db", "mysql", "user:password@tcp(localhost:3306)/testdb?parseTime=true")
	if err != nil {
		t.Fatalf("Failed to register database: %v", err)
	}

	// 准备测试数据
	err = dsunit.PrepareDatastore("test_db", "testdata/users.json")
	if err != nil {
		t.Fatalf("Failed to prepare data: %v", err)
	}

	// 执行测试逻辑
	// ...

	// 验证数据库状态
	expectations := dsunit.NewExpectation()
	expectations.AddTable("users", dsunit.NewTableExpectation(
		dsunit.WithRowCount(3),
		dsunit.WithColumnValues("status", "active"),
	))
	
	results, err := dsunit.ExpectDatastore("test_db", expectations)
	if err != nil {
		t.Fatalf("Validation failed: %v", err)
	}
	
	if !results.Valid() {
		t.Errorf("Data validation failed: %v", results)
	}
}

3. MongoDB测试示例

func TestMongoDB(t *testing.T) {
	// 注册MongoDB连接
	err := dsunit.RegisterDatastore("test_mongo", "mongodb://localhost:27017/testdb")
	if err != nil {
		t.Fatalf("Failed to register MongoDB: %v", err)
	}

	// 准备测试数据
	err = dsunit.PrepareDatastore("test_mongo", "testdata/products.json")
	if err != nil {
		t.Fatalf("Failed to prepare data: %v", err)
	}

	// 执行测试逻辑
	// ...

	// 验证MongoDB集合
	expectations := dsunit.NewExpectation()
	expectations.AddCollection("products", dsunit.NewDocumentExpectation(
		dsunit.WithDocumentCount(5),
		dsunit.WithFieldValue("category", "electronics"),
	))
	
	results, err := dsunit.ExpectDatastore("test_mongo", expectations)
	if err != nil {
		t.Fatalf("Validation failed: %v", err)
	}
	
	if !results.Valid() {
		t.Errorf("Data validation failed: %v", results)
	}
}

4. CSV文件测试示例

func TestCSVFile(t *testing.T) {
	// 注册CSV文件存储
	err := dsunit.RegisterDatastore("test_csv", "file:///path/to/csv/files")
	if err != nil {
		t.Fatalf("Failed to register CSV storage: %v", err)
	}

	// 准备测试数据
	err = dsunit.PrepareDatastore("test_csv", "testdata/orders.csv")
	if err != nil {
		t.Fatalf("Failed to prepare data: %v", err)
	}

	// 执行测试逻辑
	// ...

	// 验证CSV文件内容
	expectations := dsunit.NewExpectation()
	expectations.AddFile("orders.csv", dsunit.NewFileExpectation(
		dsunit.WithRowCount(10),
		dsunit.WithColumnValues("status", "completed"),
	))
	
	results, err := dsunit.ExpectDatastore("test_csv", expectations)
	if err != nil {
		t.Fatalf("Validation failed: %v", err)
	}
	
	if !results.Valid() {
		t.Errorf("Data validation failed: %v", results)
	}
}

测试数据文件格式

dsunit支持JSON格式的测试数据文件,例如:

{
  "users": [
    {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com",
      "status": "active"
    },
    {
      "id": 2,
      "name": "Jane Smith",
      "email": "jane@example.com",
      "status": "active"
    }
  ]
}

高级功能

  1. 数据模板:支持使用Go模板语法动态生成测试数据
  2. 变量替换:支持在测试数据中使用变量
  3. 数据序列:支持自动生成序列ID
  4. 关联数据:支持跨表/集合的数据关联

最佳实践

  1. 将测试数据外部化到JSON/CSV文件中
  2. 为每个测试用例准备独立的数据集
  3. 在测试完成后清理测试数据
  4. 使用明确的验证条件确保测试可靠性
  5. 考虑使用事务回滚来保持测试隔离性

dsunit提供了一种统一的方式来测试不同类型的数据存储,使得测试代码更加简洁和可维护。通过将测试数据外部化,可以更容易地维护和共享测试用例。

回到顶部