如何创建需要使用数据库的测试代码

我想在 GitHub 上发布我的第一个 Go 库。


我创建了一个scan_test.go有许多连接到 postgresql 数据库的测试。它不需要任何数据,只需要一个有效的连接,因为它测试静态查询结果的结果,例如select 1 union select 2。


所以我要发布包并且测试可以工作,我如何允许为测试配置数据库?出现的一个想法是使用环境变量?但官方的方式是什么?如何为我的项目正确创建测试?


我的测试文件示例:


const (

    host     = "localhost"

    port     = 5432

    user     = "ufk"

    password = "your-password"

    dbname   = "mycw"

)

type StructInt struct {

    Moshe  int

    Moshe2 int

    Moshe3 []int

    Moshe4 []*int

    Moshe5 []string

}


func TestVarsInStructInJsonArrayWithOneColumn(t *testing.T) {

    if conn, err := GetDbConnection(); err != nil {

        t.Errorf("could not connect to database: %v", err)

    } else {

        sqlQuery := `select json_build_array(json_build_object('moshe',55,'moshe2',66,'moshe3','{10,11}'::int[],'moshe4','{50,51}'::int[],

    'moshe5','{kfir,moshe}'::text[]),

                        json_build_object('moshe',56,'moshe2',67,'moshe3','{41,42}'::int[],'moshe4','{21,22}'::int[],

                                          'moshe5','{kfirrrr,moshrre}'::text[])) as moshe;`

        var foo []StructInt

        if isEmpty, err := Query(context.Background(), conn, &foo, sqlQuery); err != nil {

            t.Errorf("failed test: %v", err)

        } else if isEmpty {

            log.Fatal("failed test with empty results")

        }

        if foo[0].Moshe != 55 {

            t.Errorf("int slice test failed 21 <> %v", foo[0].Moshe)

        }

        if foo[1].Moshe2 != 67 {

            t.Errorf("int slice failed with 82 <> %v", foo[1].Moshe2)

        }

        if len(foo[1].Moshe3) != 2 {

            t.Errorf("int silice failed, array size should be 2 <> %v", len(foo[1].Moshe3))

        }

        if foo[1].Moshe3[1] != 42 {

            t.Errorf("int slice failed, moshe3[0] not 2 <=> %v", foo[1].Moshe3[1])

        }


MM们
浏览 113回答 1
1回答

Cats萌萌

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

相关分类

Go