我们[当前项目的核心](https://heupr.io/)是一个 [MemSQL](https://www.memsql.com/) 数据库,它是我们核心的数据管道;这是一个非常酷的技术,它的速度非常快,我们实在是太喜欢它了。但是,测试跟它相关的代码却有点困难,这个问题通过试验或者当遇到错误(主要是遇到错误)时,很快就可以发现。由于 Go 标准包已通过全面的测试,我只需要确保调用和依赖他们的代码在生产中也能够正常运行就好。
测试我们项目的数据库代码,我通过两个步骤完成。
通过 database/sql 包,我们有了 sql.DB 结构,它代表一系列mocks的连接,以及包含一系列与这些连接进行交互的方法。在我们的代码库中,我们使用了其中的两个(以及一个返回打开的数据库的函数):
```go
func Open(driverName, dataSourceName string) (*DB, error)
func (db *DB) Close() error
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
```
接着,我像下面这样创建了一个名为 sqlDB 的接口:
```go
type sqlDB interface {
Open(driverName, dataSourceName string) (*sql.DB, error)
Close() error
Query(query string, args ...interface{}) (*sql.Rows, error)
}
```
这是一个 “曲线救国” 的想法,我定义了一个由 sql.DB 结构方法实现的接口。有了这个接口,再加上单元测试可以直接使用测试对象,立马就可以测试围绕这些函数/方法的调用代码。请注意,由于在返回值中依赖了诸如 sql.Rows 之类的,导致需要一些额外的配置,但它确实让需要测试的范围更接近于实际的 database/sql 包(即,需要测试的东西更加少)。
接着,我构建第二个步骤的测试。定义了一个 dataAccess 接口,其中包含返回,将供后面处理的,准备好的对象的特定方法。这些函数将调用上面的 sqlDB 接口定义的方法,(下面的)这些方法从我们的代码库和单元测试中进一步封装了 database/sql 包:
```go
type dataAccess interface {
readIntegrations(query string) (map[int64]*integration, error)
readSettings(query string) (map[int64]*settings, error)
readEvents(query string) (map[int64][]*preprocess.Container, error)
}
```
再一次使用接口,可以让我们在测试中替换更多的生产代码,并让我们在调用这些接口代码时,可以关注(更多)不同的测试用例和场景。
简单地说:
- sqlDB 接口可以让我们立即测试与数据库对象交互的相关代码(而不需要真的启动一个数据库并注入各种表) - (例如)测试处理数据库查询之类的东西
- dataAccess 接口允许我们对依赖它的值进行单元测试,例如上面返回的 map 结果 - 后面的想法也都是这样
对(依赖于)数据库相关的代码进行单元测试有不同的方法,而这就是我在 Go 项目中采用的方法 - 我非常乐意提供(我的)建议,或者方案,以及快乐地进行单元测试的方法!
via: https://dev.to/forstmeier/golang-database-mocks-1hm9
作者:John Forstmeier 译者:gogeof 校对:rxcai
本文由 GCTT 原创翻译,Go语言中文网 首发。也想加入译者行列,为开源做一些自己的贡献么?欢迎加入 GCTT!
翻译工作和译文发表仅用于学习和交流目的,翻译工作遵照 CC-BY-NC-SA 协议规定,如果我们的工作有侵犯到您的权益,请及时联系我们。
欢迎遵照 CC-BY-NC-SA 协议规定 转载,敬请在正文中标注并保留原文/译文链接和作者/译者等信息。
文章仅代表作者的知识和看法,如有不同观点,请楼下排队吐槽
有疑问加站长微信联系(非本文作者))