Go:如何运行多个包的测试?

wb1gzix0  于 2023-03-27  发布在  Go
关注(0)|答案(5)|浏览(186)

我在src/下的子目录下有多个包,用go test对每个包运行测试都很好。
当尝试使用go test ./...运行所有测试时,测试正在运行,但失败。
测试是针对本地数据库服务器运行的,每个测试文件都具有带DB指针的全局变量。
我尝试使用-parallel 1运行测试以防止数据库中的争用,但测试仍然失败。
这里的问题是什么?
编辑:一些测试在丢失数据库条目时失败,我在每次测试之前和之后完全清除数据库。我能想到的唯一原因是测试之间的一些争用。
编辑2:
我的每个测试文件都有2个全局变量(使用mgo):

var session *mgo.Session
var db *mgo.Database

它还具有以下设置和拆卸功能:

func setUp() {
   s, err := cfg.GetDBSession()
   if err != nil {
       panic(err)
   }

   session = s

   db = cfg.GetDB(session)

   db.DropDatabase()
}

func tearDown() {
   db.DropDatabase()

   session.Close()
}

每个测试使用setUp()defer tearDown()启动
cfg也是:

package cfg

import (
    "labix.org/v2/mgo"
)

func GetDBSession() (*mgo.Session, error) {
    session, err := mgo.Dial("localhost")

    return session, err
}

func GetDB(session *mgo.Session) *mgo.Database {
    return session.DB("test_db")
}

编辑3:
我更改了cfg以使用随机数据库,测试通过。似乎来自多个包的测试在某种程度上并行运行。
是否可以强制go test在包中顺序运行所有内容?

lp0sw83n

lp0sw83n1#

更新:正如@Gal Ben-Haim所指出的,添加go test -p 1标志(未记录)可以串行地构建和测试所有的包,正如Go语言源代码中的testflag用法消息所指出的:

-p=n:并行构建和测试多达n个包

旧答案

当运行go test ./...时,不同包的测试实际上是并行运行的,即使您设置了parallel=1(只有特定包中的测试才保证一次运行一个)。如果按顺序测试包很重要,比如涉及数据库设置/拆卸时,看起来现在唯一的方法是使用shell来模拟go test ./...的行为,并强制一个接一个地测试包。
例如,在Bash中可以这样做:

find . -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test

该命令首先列出包含*.go文件的所有子目录。然后使用sort -u仅列出每个子目录一次(删除重复项)。最后通过xargs将包含go文件的所有子目录提供给go test-P1表示一次最多运行一个命令。
不幸的是,这比仅仅运行go test ./...要难看得多,但如果将其放入shell脚本或别名到更令人难忘的函数中,它可能是可以接受的:

function gotest(){   find $1 -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test; }

现在所有测试都可以在当前目录中运行,方法是调用:

gotest .
zi8p0yeb

zi8p0yeb2#

显然,运行go test -p 1会按顺序运行所有内容(包括构建),但我在go help testgo help testflag中没有看到此参数

ctrmrzij

ctrmrzij3#

我假设,因为包单独通过,在这种情况下,您也会在测试之前删除DB。
因此,听起来每个包测试的DB状态都应该是空的。
因此,在每一组包测试之间,DB必须清空。有两种方法可以解决这个问题,不知道你的整个情况,我将简要解释这两种选择:

选项1.测试设置

在每个package _test文件的开头添加一个init()函数,然后放置处理以删除DB。这将在实际包的init()方法之前运行:

func init() {
    fmt.Println("INIT TEST")
    // My test state initialization
    // Remove database contents
}

假设包也有类似的打印行,您将在输出中看到(注意,只有当a测试失败或您提供-v选项时,才会显示stdout输出)。

INIT TEST
INIT PACKAGE

选项2.模拟数据库

为数据库创建一个mock(除非你特别要测试的是这个数据库)。对于每个测试的开始状态,mock数据库总是可以表现得像数据库是空白的。

vxf3dgd4

vxf3dgd44#

我使用了一种廉价的方法来选择多个包中的测试。

go test -v ./... -run "TestUnit?"

只要给你的测试命名,让他们被抓住:
func TestUnitCountriesStructs(t *testing.T)
您提到需要对测试进行某种设置和拆卸。我使用testify。简而言之:

import (
    "testing"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/suite"
)

type ExampleTestSuite struct {
    suite.Suite
    VariableThatShouldStartAtFive int
}

// before each test
func (suite *ExampleTestSuite) SetupTest() {
    suite.VariableThatShouldStartAtFive = 5
}

func (suite *ExampleTestSuite) TestExample() {
    assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
    suite.Equal(5, suite.VariableThatShouldStartAtFive)
}

func TestUnitExampleTestSuite(t *testing.T) {
    suite.Run(t, new(ExampleTestSuite))
}
daupos2t

daupos2t5#

请尝试以下github仓库。
https://github.com/appleboy/golang-testing
coverage.sh复制到/usr/local/bin/coverage并更改权限。

$ curl -fsSL https://raw.githubusercontent.com/appleboy/golang-testing/master/coverage.sh /usr/local/bin/coverage
$ chmod +x /usr/local/bin/coverage

相关问题