1 回答

TA贡献1805条经验 获得超9个赞
一种典型的方法是将TestMain的使用与一组记录在案的环境变量和/或命令行选项结合起来,这些变量可以传递给为运行特定包的测试而构建的测试二进制文件。
基本上,TestMain读取环境和/或命令行选项,验证它们,可能会填充一些可用于测试套件的导出变量,然后运行套件。
在我的 $dayjob 中,我们使用所描述的方法和一个名为 like 的辅助函数SkipIfNoDatabase(t *testing.T),它检查由 TestMain 设置的状态,如果所需的配置与未提供数据库连接。这允许在不设置数据库的情况下运行测试套件——所有需要的测试都将被跳过。
下面是在 Gitlab CI 中运行测试的示例。
在.gitlab-ci.yml一个项目中,除其他外,还包含类似
stages:
- test
.golang_stage:
image: internal-corporate-registry:5000/go-test:1.14
variables:
MONGODB_URI: 'mongodb://test-mongodb:27017'
services:
- name: mongo:3.6-xenial
alias: test-mongodb
test_golang:
extends: .golang_stage
stage: test
tags:
- common
only:
- pushes
- schedules
script:
- make test
- make build
这个配置确保当我们使用 MongoDB 实例的 Go 程序被测试时,mongo:3.6-xenialDocker 镜像被拉取并运行,并被分配一个主机名test-mongodb;MONGODB_URI环境变量设置为引用正在运行的 MongoDB 实例。
现在该程序lib/testing/testdb具有包含
package testdb
import (
"io"
"os"
"testing"
)
// DBName is the MongoDB database name to be used in tests.
const DBName = "blah_blah_test"
var (
// MongoDBURI identifies a MongoDB instance to use by testing suite.
MongoDBURI string
// Enabled is only set to true if the MongoDB URI was made available
// to the test suite. It can be used by individual tests to skip
// execution if an access to a MongoDB instance is required to perform
// the test.
Enabled bool
)
// Initialize initializes the package's global state.
//
// Initialize is intended to be called once per package being tested -
// typically from the package's TestMain function.
func Initialize() {
MongoDBURI = os.Getenv("MONGODB_URI")
if MongoDBURI == "" {
Enabled = false
io.WriteString(os.Stderr,
"Empty or missing environment variable MONGODB_URI; related tests will be skipped\n")
return
}
Enabled = true
}
// SkipIfDisabled skips the current test if it appears there is no
// MongoDB instance to use.
func SkipIfDisabled(t *testing.T) {
if !Enabled {
t.Skip("Empty or missing MONGODB_URI environment variable; skipped.")
}
}
…然后每个使用数据库的包都包含一个名为的main_test.go文件
package whatever_test
import (
"testing"
"acme.com/app/lib/testing/testdb"
"acme.com/app/lib/testing/testmain"
)
func TestMain(m *testing.M) {
testdb.Initialize()
testmain.Run(m)
}
测试本身就是这样滚动的
package whatever_test
import (
"testing"
"acme.com/app/lib/testing/testdb"
)
func TestFoo(t *testing.T) {
testdb.SkipIfDisabled(t)
# Do testing
}
testmain是另一个内部包,它导出Run运行测试的函数,但在此之前它会处理额外的初始化:设置应用程序代码的日志记录并确定是否要求运行压力测试(仅在晚上运行,已安排) .
package testmain
import (
"flag"
"os"
"testing"
"acme.com/app/lib/logging"
)
// Stress is true if the stress tests are enabled in this run
// of the test suite.
var Stress bool
// Run initializes the package state and then runs the test suite the
// way `go test` does by default.
//
// Run is expected to be called from TestMain functions of the test suites
// which make use of the testmain package.
func Run(m *testing.M) {
initialize()
os.Exit(m.Run())
}
// SkipIfNotStress marks the test currently executed by t as skipped
// unless the current test suite is running with the stress tests enabled.
func SkipIfNotStress(t *testing.T) {
if !Stress {
t.Skip("Skipped test: not in stress-test mode.")
}
}
func initialize() {
if flag.Parsed() {
return
}
var logFileName string
flag.BoolVar(&Stress, "stress", false, "Run stress tests")
flag.StringVar(&logFileName, "log", "", "Name of the file to redirect log output into")
flag.Parse()
logging.SetupEx(logging.Params{
Path: logFileName,
Overwrite: true,
Mode: logging.DefaultFileMode,
})
}
运行压力测试的项目的相关位Makefile如下所示:
STRESS_LOG ?= stress.log
.PHONY: all test build stress install/linter
all: test build
build:
go build -ldflags='$(LDFLAGS)'
test:
go test ./...
stress:
go test -v -run=Stress -count=1 ./... -stress -log="$(STRESS_LOG)"
…以及运行压力测试的 CI 配置读取
stress:
extends: .golang_stage
stage: test
tags:
- go
only:
- schedules
variables:
STRESS_LOG: "$CI_PROJECT_DIR/stress.log"
artifacts:
paths:
- "$STRESS_LOG"
when: on_failure
expire_in: 1 week
script:
- make stress
- 1 回答
- 0 关注
- 111 浏览
添加回答
举报