【发布时间】:2023-02-07 23:42:57
【问题描述】:
我一直在努力研究单元测试、依赖注入、tdd 和所有这些东西,例如,我一直坚持测试进行数据库调用的函数。
假设您有一个接受数据库接口的 PostgresStore 结构,该接口具有 Query() 方法。
type PostgresStore struct {
db Database
}
type Database interface {
Query(query string, args ...interface{}) (*sql.Rows, error)
}
你的 PostgresStore 有一个 GetPatients 方法,它调用数据库查询。
func (p *PostgresStore) GetPatient(id int) ([]Patient, error) {
rows, err := p.db.Query("SELECT id, name, age, insurance FROM patients")
if err != nil {
return nil, err
}
defer rows.Close()
items := []Patient{}
for rows.Next() {
var i Patient
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Surname,
&i.Age,
&i.InsuranceCompany,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
在实际实现中,您只需将 *sql.DB 作为数据库参数传递,但是你们如何使用伪造的数据库结构编写单元测试?
【问题讨论】:
-
AFAICT 你的主要问题是你的
Database接口直接依赖于一种类型,没有简单的方法来提供有效的测试值,即*sql.Rows。所以你要么不应该模拟Database,而是应该实现一个模拟database/sql/driver。或者您需要将接口更改为不依赖于您无法控制的类型,而是依赖于您拥有可能需要的所有控制权的类型(即接口类型)。 -
嘿伙计,这就是答案。你能给我指出一些资源或 github 项目来实现你刚才解释的内容吗?我很难弄清楚这一点哈哈。谢谢
-
就个人而言,我不会。
GetPatient除了与数据库交互之外什么都不做,因此使用模拟数据库对其进行测试的价值有限。我会用模拟Store对任何调用GetPatient进行单元测试,并且只一体化使用测试 PostgreSQL 数据库测试PostgresStore本身。