Help us shape the future of Go! Take the 2026 Go Developer Survey

fixture

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 7, 2019 License: MIT Imports: 12 Imported by: 0

README

FIXTURE, easily load or export test fixtures

Build Status Coverage Status Go Report Card

  __ _      _
 / _(_)_  _| |_ _   _ _ __ ___
| |_| \ \/ / __| | | | '__/ _ \
|  _| |>  <| |_| |_| | | |  __/
|_| |_/_/\_\\__|\__,_|_|  \___|

目录

介绍

我们在 Python 项目中写单元测试时,一般需要准备测试数据并在启动单元测试时使用 @fixture('foo.sql') 的方式导入到数据库。

让我们回顾下,使用 SQL 格式的测试数据存在什么问题:

  1. 造测试数据非常麻烦,如果某个表的字段较多时,更为严重,可能存在某些字段填的值没和期望的列名对应上;
  2. 纯 SQL 虽然可以方便地从数据库直接复制导入,但是后期编辑和维护比较麻烦。

受到开源项目 theiconic/fixtures 和 zhulongcheng/testsql 的启发,打算使用 YAML/JSON 编写测试数据。当然,这里极力推荐 YAML 格式,方便人肉编辑!

功能

注意:目前仅支持 MySQL 或者符合 MySQL 协议的数据库

  • 优雅的接口:方便在测试代码中使用测试数据
  • 支持 JSON/YAML/SQL 格式测试数据导入数据库
  • 支持从数据库指定表中生成测试数据(支持 JSON/YAML/SQL 格式导出)
  • 格式可扩展:除了默认支持的 JSON/YAML/SQL 格式外,也支持自定义格式,只需要实现相关接口即可(直接提 PR)

安装

go get -u github.com/marshalys/fixture

示例

首先,假设包含测试数据的项目结构如下:

.
├── testdata 这里放测试数据
│   ├── fixtures
│   │   ├── user.yml 文件名默认为表名,每个文件都是针对单个表的测试数据
│   │   ├── topic.json 同样支持 JSON 格式数据
│   │   └── product.yml
│   └── schema.sql
└── thrifts

下面我们看在单元测试中如何使用这个工具。

配置

首先我们需要告诉该工具一些测试的配置,建议在项目的 pkg/configs 包中新建一个文件 fixture.go,目录结构类似:

configs
└── fixture.go

在 fixture.go 中添加下面的代码,方便 fixture 启动时知道去哪儿读取 schema 和测试数据配置:

func NewDefaultTestFixture() *fixture.TestFixture {
	return fixture.New(
		fixture.Database(getTestDBRawURL()),
		fixture.SchemaFilepath(path.Join(getTestDataPath(), "schema.sql")),
		fixture.DataDir(path.Join(getTestDataPath(), "fixtures")),
	)
}

func getTestDBRawURL() string {
	dsnFmt := "mysql://%s:%s@%s/%s?charset=utf8&parseTime=true&loc=Asia/Shanghai"
	return fmt.Sprintf(dsnFmt,
		os.Getenv("MYSQL_USERNAME"),
		os.Getenv("MYSQL_PASSWORD"),
		os.Getenv("MYSQL_HOST"),
		os.Getenv("MYSQL_DATABASE"),
	)
}

// getTestDataPath 返回测试夹具数据路径
func getTestDataPath() string {
	_, f, _, _ := runtime.Caller(1)
	curDir := path.Dir(f)
	// 找到项目 root 目录
	// 类似 ../../curDir
	root := path.Dir(path.Dir(curDir))
	return path.Join(root, "testdata")
}

使用姿势

type SuiteExampleTester struct {
	suite.Suite
	tf *fixture.TestFixture
}

func (s *SuiteExampleTester) SetupSuite() {
	s.tf = NewDefaultTestFixture()
}

func (s *SuiteExampleTester) TearDownSuite() {
	s.tf.DropTables()
}

func (s *SuiteExampleTester) TestFoo() {
	scope := s.tf.Use("table_a", "table_b")
	defer scope.Clear()

	// 填写测试逻辑
}

func (s *SuiteExampleTester) TestBar() {
	s.tf.Use("table_a", "table_b").Test(func () {
		// 在该闭包中填写测试逻辑
		// 测试完毕后,会自动清空表
	})
}

导出

啊,我不想一开始就手写 YAML/JSON/SQL!我希望能利用测试环境中的数据,然后再在输出结果的基础上修改为想要的测试数据!没问题,fixture 目前已经支持导出数据为这三种格式啦!

安装

$ go get github.com/marshalys/fixture/fixturegen

检查下是否安装正确(确保你的 $GOPATH 在 $PATH 环境变量中!)

$ which fixturegen
# 输出结果类似这样:
`$GOPATH`/bin/fixturegen

# 查看下帮助
$ fixturegen --help

Usage of fixturegen:
  -ext string
    	output file extension (e.g. '.yml', '.json') (default ".yml")
  -o string
    	output directory (default ".")
  -q string
    	custom query sql
  -t string
    	table to be exported
  -url string
    	database connection url

使用姿势

下面我们看看怎么使用它生成想要的测试数据:

# 默认会生成 YAML 格式文件,并使用默认的数据查询策略(只查 5 条,并基于 id 排序)
# 输出的文件默认在工作目录下
$ fixturegen -url mysql://localhost:3306/test_todo_api -t user

# 可以指定别的格式输出
$ fixturegen -url mysql://localhost:3306/test_todo_api -t user -ext [.json/.ext/.yml]

# 当然,也可以指定输出数据到别的目录
$ fixturegen -url mysql://localhost:3306/test_todo_api -t user -o path/to/testdata/fixtures

# 哦哦,还可以自定义查询语句(注意:只支持简单的查询语句)
$ fixturegen -url mysql://localhost:3306/test_todo_api -t user -q "SELECT * FROM user WHERE id > 100 LIMIT 10"

主要 API 说明

  • TestFixture.New: 新建 TestFixture 实例,需要用户提供数据库、测试数据配置
  • TestFixture.Use: 使用指定表的测试数据填充到测试数据库对应表中
  • TestFixture.DropTables: 用于测试结束后删除测试表(注意,fixture 工具不会随意自动删除表,所以作为用户的你需要显式调用才会删除表)
  • TestFixture.TableNames: 通过 schema.sql 读取到的所有表名
  • TestFixture.Config: 可以获取详细配置信息
  • Scope.Clear: 用于某个单元测试结束后,清空表数据
  • Scope.Test: 可接收一个测试函数,运行测试函数后自动清空表

Help & Dev & Bug Report

如有任何想要的新功能或者是发现的 Bug 均可提到 issue 中~

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrFixtureDataDirNotFound = errors.New("fixture data dir not found")
	ErrSchemaFileNotFound     = errors.New("schema file not found")
	ErrMissingDBRawURL        = errors.New("database url is not configured")
	ErrDriverNotSupported     = errors.New("only mysql driver is officially supported")
)

Functions

func RegisterExporter

func RegisterExporter(dataFmt DataFormat, ext string, exporter Exporter)

func RegisterLoader

func RegisterLoader(dataFmt DataFormat, ext string, loader Loader)

Types

type Config

type Config struct {
	DatabaseURL    *DatabaseURL
	FixtureDataDir string
	SchemaFilepath string
}

func (*Config) Validate

func (c *Config) Validate() error

type DataFormat

type DataFormat int
const (
	SQL DataFormat = iota
	YAML
	JSON
)

func LookupDataFormatByExt

func LookupDataFormatByExt(ext string) (DataFormat, bool)

func (DataFormat) String

func (f DataFormat) String() string

type DatabaseURL

type DatabaseURL struct {
	// contains filtered or unexported fields
}

func Parse

func Parse(rawurl string) (*DatabaseURL, error)

func (*DatabaseURL) DBName

func (dbURL *DatabaseURL) DBName() string

func (*DatabaseURL) DSN

func (dbURL *DatabaseURL) DSN() string

func (*DatabaseURL) Driver

func (dbURL *DatabaseURL) Driver() string

func (*DatabaseURL) String

func (dbURL *DatabaseURL) String() string

type Exporter

type Exporter interface {
	Export(tableName string, columns []string, rawRows [][][]byte) ([]byte, error)
}

func LookupExporter

func LookupExporter(format DataFormat) Exporter

type Loader

type Loader interface {
	Load(filename string) (string, error)
}

func LookupLoader

func LookupLoader(dataFmt DataFormat) Loader

type Option

type Option func(*TestFixture)

func DataDir

func DataDir(dir string) Option

func Database

func Database(rawurl string) Option

func SchemaFilepath

func SchemaFilepath(p string) Option

type Scope

type Scope struct {
	// contains filtered or unexported fields
}

func (*Scope) Clear

func (s *Scope) Clear()

Clear just drop the selected tables, simple and clear

func (*Scope) Test

func (s *Scope) Test(testFunc func())

type TestFixture

type TestFixture struct {
	// contains filtered or unexported fields
}

func New

func New(opts ...Option) *TestFixture

func (*TestFixture) Config

func (tf *TestFixture) Config() *Config

func (*TestFixture) DropTables

func (tf *TestFixture) DropTables()

DropTables drops all the test tables

func (*TestFixture) String

func (tf *TestFixture) String() string

func (*TestFixture) TableNames

func (tf *TestFixture) TableNames() []string

func (*TestFixture) Use

func (tf *TestFixture) Use(tableNames ...string) *Scope

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL