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

问题描述 投票:0回答:5

我在src/下的一个子目录下有多个包, 使用

go test
为每个包运行测试工作正常。

当尝试使用

go test ./...
运行所有测试时,测试正在运行但失败..

测试是针对本地数据库服务器运行的,每个测试文件都有带有数据库指针的全局变量。

我尝试使用

-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
跨包顺序运行所有内容?

unit-testing go mgo
5个回答
21
投票

更新:正如@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
只列出每个子目录一次(删除重复项)。最后,所有包含 go 文件的子目录都通过
go test
提供给
xargs
-P1
表示一次最多运行一个命令。

不幸的是,这比运行

go test ./...
更难看,但如果将它放入 shell 脚本或别名到更令人难忘的函数中,它可能是可以接受的:

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

现在所有测试都可以通过调用在当前目录中运行:

gotest .

13
投票

显然运行

go test -p 1
按顺序运行所有内容(包括构建),我没有在
go help test
go help testflag

中看到这个论点

0
投票

我假设因为在这种情况下包单独通过,所以您也在该测试之前也删除了数据库。

因此听起来每个包测试的数据库状态都应该是空的。
因此,在每组包测试之间,必须清空数据库。有两种解决方法,不知道你的整个情况,我将简要解释这两种选择:

选项 1. 测试设置

在每个包 _test 文件的开头添加一个

init()
函数,然后将其处理以删除数据库。这将在实际包的
init()
方法之前运行:

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

假设包也有类似的打印行,您会在输出中看到(请注意,stdout 输出仅在测试失败或您提供

-v
选项时显示)

INIT TEST
INIT PACKAGE

选项2.模拟数据库

为数据库创建一个模拟(除非那是你正在测试的)。对于每个测试的开始状态,模拟数据库总是可以像数据库是空白的一样。


0
投票

我用了一种便宜的方式在多个包裹中提取测试。

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))
}

-1
投票

请尝试以下 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
© www.soinside.com 2019 - 2024. All rights reserved.