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

Posted

技术标签:

【中文标题】Go:如何为多个包运行测试?【英文标题】:Go: how to run tests for multiple packages? 【发布时间】:2014-07-06 02:07:28 【问题描述】:

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

【问题讨论】:

错误信息是什么?你使用任何文件吗?当go test 从不同的目录启动时,相对路径可能会出错。 究竟是什么失败了?您提供的信息越多,我们能为您提供的帮助就越多。 要明确:上述问题的答案是go test ./...。我每天都这样做。您还有其他一些与您的具体情况相关的问题,您需要更清楚地提出该问题。 一些测试似乎因为缺少数据库条目而失败,我在每次测试之前和之后完全删除了数据库,所以我能想到的唯一原因是在运行 go test ./... 时会发生这种情况并且一切都通过了运行单个测试文件时是因为测试之间存在争用... “每次测试之前和之后”是什么意思?你是如何实施的?一个简化的测试示例在这里会大有帮助。 【参考方案1】:

更新:正如@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 文件的子目录都通过xargs 提供给go test-P1 表示一次最多运行一个命令。

不幸的是,这比只运行go test ./... 丑多了,但如果将其放入 shell 脚本或别名为更容易记住的函数,这可能是可以接受的:

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

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

gotest .

【讨论】:

哦,哇,你说得对——我实际上在发布这个答案之前检查了 Go 源代码,但不知何故仍然没有注意到那个选项。【参考方案2】:

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

【讨论】:

它在里面:golang.org/cmd/go/#hdr-Compile_packages_and_dependencies : "-pn 可以并行运行的程序的数量,例如构建命令或测试二进制文件。默认是可用的 CPU 数量,除了 on darwin/arm 默认为 1。"【参考方案3】:

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

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

选项 1. 测试设置

在每个包 _test 文件的开头添加一个init() 函数,然后您对其进行处理以删除数据库。这将在实际包的init() 方法之前运行:

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

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

INIT TEST
INIT PACKAGE

选项 2. 模拟数据库

为数据库创建一个模拟(除非这是您正在测试的具体内容)。对于每个测试的开始状态,模拟数据库总是可以表现得就像数据库是空白一样。

【讨论】:

我在问题中添加了更多信息,我在每次测试之前和之后所做的还不够吗? 根据您在第二次编辑中添加的内容,据我所知,这似乎已经足够了。也许它的数据库服务器限制妨碍了? 它只是 Ubuntu 上本地安装的 Mongodb。我使用 Python 或 Node.js 对其进行类似测试没有问题。 测试是否有可能以某种方式并行运行?【参考方案4】:

请尝试以下 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

【讨论】:

以上是关于Go:如何为多个包运行测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何为Linux安装Go语言

如何为 Python 中唯一的项目测试多个集合?

如何为Linux安装Go语言

如何为具有多个模式分布的Controller编写单元测试

如何为完成端口创建多个线程?

如何为多个构建配置选择不同的 app.config