为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
MM们 2022-07-25 10:52:56
我想在 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])        }
查看完整描述

1 回答

?
Cats萌萌

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


查看完整回答
反对 回复 2022-07-25
  • 1 回答
  • 0 关注
  • 111 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号