【问题标题】:Testing database interactions测试数据库交互
【发布时间】: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,或者,至少给你一些示例代码。

标签: database go testing


【解决方案1】:

我在集成测试方面没有太多经验,我不确定模拟数据库驱动程序是否适合你,但如果是这样,我一直在使用go-sqlmock 包来模拟 sql 数据库结果单元测试和工作就像一个魅力。您可以使用它并为每个测试提供一个单独的“数据库引擎”。这有点费时,因为您必须手动告诉 mock 期望什么查询以及返回什么但相信我,这是一个很好的时间投资。

正如我之前所说,我不确定使用此策略是否适合您的情况,因为如果您有兴趣了解您的应用程序在“真实数据库场景”中的行为方式,例如验证注册表是否实际保存,然后模拟数据库结果有点没用。

【讨论】:

  • 感谢您的建议,但在我的存储层中,我想测试真实的数据库交互,检查我的查询是否正确以及是否可以将不同的数据插入到数据库中。我正在考虑使用 go-sqlmock,但在这种情况下它不会保持集成测试,我只会测试代码部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-06
  • 2013-12-04
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 2014-06-10
  • 2017-09-16
相关资源
最近更新 更多