>我写了一个函数:
func AllItems(w http.ResponseWriter, r *http.Request) {
db, err := gorm.Open("sqlite3", "test.db")
if err != nil {
panic("failed to connect database")
}
defer db.Close()
var items [] Item
db.Find(&items)
fmt.Println("{}", items)
json.NewEncoder(w).Encode(items)
}
我想对此进行单元测试。理想情况下,单元测试意味着需要测试函数的每一行。我不确定我应该如何测试数据库连接是否已打开,然后它是否显示数据库的所有内容。我应该如何测试此代码?
此函数是简单 CRUD 应用程序的 GET 终结点。代码在这里。
重构代码并将其分解为较小的、可测试的函数,并将依赖项传递给这些函数。还要为依赖项创建接口,以便更轻松地进行测试。
例如:
type myDatabaseInterface interface {
Find(interface{}) // this signature should match the real db.Find()
}
func AllItems(w http.ResponseWriter, r *http.Request) {
db, err := gorm.Open("sqlite3", "test.db")
if err != nil {
panic("failed to connect database")
}
defer db.Close()
items := findItems(db)
json.NewEncoder(w).Encode(items)
}
func find(db myDatabaseInterface) ([]Item) {
var items []Item
db.Find(&items)
return items
}
然后,您可以为依赖项创建模拟并在测试中使用它们:
type mock struct {}
// mock should implement myDatabaseInterface to be able to pass it to the function
func (m *mock) Find(interface{}) {
// implement the mock to satisfy your test
}
func Test_find(t *testing.T) {
m := mock{}
res := find(m)
// do testing
}
与其每次处理请求时都调用Open
,也许您应该在外部打开它并使其可用于您的函数。这样处理程序就会变得如此之小,以至于无需对其进行实际测试:
func makeAllItemsHandler(db myDatabaseInterface) func(http.ResponseWriter, *http.Request) {
return func(http.ResponseWriter, *http.Request) {
items := findItems(db)
json.NewEncoder(w).Encode(items)
}
}
然后,您可以在设置应用程序时一劳永逸地创建一个数据库,并将其传递给需要它的函数,从而从函数中删除难以测试的代码。