如何使用接口正确模拟某些*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)
答案 0 :(得分:1)
我建议嘲笑数据库是一个坏主意。您可以验证是否使用特定的SQL字符串调用查询并返回虚假结果,但这确实没用。这些测试增加了很少的价值并且增加了一种虚假的自信心。测试接受的内容与数据库中实际运行的内容之间绝对没有联系。
真正的危险之一是您的数据库架构可能会发生变化,但您的模拟不会更新。然后你的代码将在生产中失败但通过测试。
相反,实现某种数据抽象层,例如,像Data Access Object(DAO)。
您可以编写自动集成测试,以针对您的数据库测试DAO。这将确保您的DAO实际工作并捕获任何错误,例如在架构更改后未更新的查询。
然后,您可以为其他代码编写单元测试。任何与数据库交互的东西都应该使用mock / stub / fake DAO,具体取决于测试所需的内容。
答案 1 :(得分:0)
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)
}