【问题标题】:Mocking database return types with interfaces使用接口模拟数据库返回类型
【发布时间】:2018-01-17 16:45:52
【问题描述】:

如何正确模拟一些*sql.DB 使用接口进行单元测试的方法?例如,我想要一个 Store 结构,用作我的处理程序的数据源。它有一个conn 字段,即*sql.DB。但是在我的测试中,我想模拟数据库,所以我尝试返回的不是实际的*sql.Rows,而是*sql.Rows 应该满足的接口。代码如下:

type TestRows interface {
    Scan ()
}

type TestDB interface {
    Query (query string, args ...interface{}) (TestRows, error) 
}

type Rows struct {
    //..
}

func (r *Rows) Scan () {
    fmt.Println("Scanning")
}

这是*sql.DB

type DB struct {
    //...
}

func (d *DB) Query (query string, args ...inteface{}) (*Rows, error) {
    return &Rows{/* .... */}, nil
}

当我想实例化 Store 时,它会抛出错误

type Store struct {
    conn TestDB
}

func main() { 
    cl := Store {conn: &DB{}}
    fmt.Println("Hello, playground")
}

cannot use DB literal (type *DB) as type TestDB in field value:
    *DB does not implement TestDB (wrong type for Query method)
        have Query(string) (*Rows, error)
        want Query(string) (TestRows, error)

【问题讨论】:

  • 不幸的是,函数签名必须完全匹配才能满足接口,并且func(string) TestRowsfunc(string) *Rows 不同即使 *Rows 满足TestRows 接口。但是,有一些数据库模拟库可以解决这个问题,我的建议是使用其中之一。
  • 谢谢@AlexGuerra。

标签: go mocking


【解决方案1】:

我建议模拟数据库是个坏主意。您可以验证是否使用特定的 SQL 字符串调用查询并返回虚假结果,但这确实没有用。这些测试几乎没有增加价值,并且会产生错误的信心。您的测试接受的内容与您的数据库中实际运行的内容之间绝对没有联系。

真正的危险之一是您的数据库架构可能会更改,但您的模拟不会更新。然后您的代码将在生产中失败但通过测试。

相反,实现某种数据抽象层,例如就像Data Access Object (DAO)。

您可以编写自动集成测试来针对您的数据库测试您的 DAO。这将确保您的 DAO 实际工作并捕获任何错误,例如架构更改后查询未更新。

然后您可以为您的其他代码编写单元测试。任何与数据库交互的东西都应该使用模拟/存根/假 DAO,具体取决于测试的要求。

【讨论】:

    【解决方案2】:

    Query函数的定义需要是:

    func (d *DB) Query(query string, args ...interface{}) (TestRows, error) {
        return &Rows{count: 1}, nil
    }
    

    编辑:

    如果如——你指出的——你不能改变Query函数的实现,因为你需要满足其他接口,那么你需要调整你自己的接口。在这种情况下

    type TestDB interface {
        Query(query string, args ...interface{}) (*Rows, error)
    }
    

    【讨论】:

    • 嗯,这是database/sql 包中Query 方法的定义。我无法改变这一点。
    • 查看我对答案的编辑。您提供的代码与此一起运行...当然,由于此更改,可能还有其他代码无法正常工作。您还必须进行调整。
    • 谢谢@TehSphinx。但是,在这种情况下,TestDB 变得依赖于 *Rows 的实际实现,这不是我想要的。
    • 我想你别无选择,只能使用 @AlexGuerra 建议的数据库模拟库
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多