【发布时间】:2019-12-26 14:25:48
【问题描述】:
我有一个具有存储层的 API。它只进行数据库交互并执行 CRUD 操作。现在我想测试这些功能。 在我的路径 API/storage/ 中,我有不同的包,它们具有与同一数据库中的不同表交互的功能。表 A、B 和 C 在同一个数据库中。
我的文件层次结构如下:
--api
--storage
--A
--A.go
--A_test.go
--B
--C
--server
--A
--testData
--A.sql
--B.sql
这样我想用命令测试整个存储层
go test ./...
我遵循的方法是我有一个函数 RefreshTables,它首先截断表格,然后用我保存在 testData 文件夹中的固定测试数据填充它。为了截断我做:
db.Exec("SET FOREIGN_KEY_CHECKS = 0;")
db.Exec("truncate " + table)
db.Exec("SET FOREIGN_KEY_CHECKS = 1;")
默认情况下,go test 会并行运行不同包的测试功能,会创建多个 sql 连接,truncate 在其他一些连接上运行,而 set foreign key 在一些连接上运行其他连接随机从连接池中。
如果一起运行,我无法通过我的测试,但如果单独运行或打包运行,所有测试都会通过。
如果我这样做:
go test ./... -p 1
这使得测试函数一个接一个地运行,所有的测试都通过了。
我也尝试过在截断之前使用截断和锁定表的事务。
我查看了这篇文章 (https://medium.com/kongkow-it-medan/parallel-database-integration-test-on-go-application-8706b150ee2e),他建议在每个测试函数中创建不同的数据库,并在函数结束后删除该数据库。我认为这将非常耗时。
如果有人建议在 Golang 中测试数据库交互的最佳方法,那将非常有帮助。
【问题讨论】:
-
每个包(不是每个函数)使用一个数据库。默认情况下,包中的函数不会并行执行,因此可以共享数据库。
-
@Peter 我有一种情况,A 是品牌,B 是产品。产品具有品牌 ID。要使用外键约束刷新与品牌相关的产品,我需要先拥有该品牌,因此需要先刷新品牌,然后再刷新 B 中的产品。所以这是我的方法失败的地方。我还想在将来在包中添加并行测试。
-
您尝试过使用测试容器吗?您可以为每个包启动单独的容器
-
您正在实施什么样的测试?单元测试还是集成测试?
-
对于工作中的集成测试,我的团队一直在使用testify suites。该套件有一个
SetupAllSuite钩子,它在任何测试运行之前被调用并启动一个postgresql 容器。在我们的AfterTest挂钩中,我们从所有表中删除数据。而且,在我们的TearDownAll钩子中,我们销毁了 docker 容器。我会考虑为 testify 套件开源这个 mixin,或者,至少给你一些示例代码。