单元测试Go具有ORM交互的函数

Fly*_*ura -1 unit-testing mocking go testify

我写了一个函数:

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)
}
Run Code Online (Sandbox Code Playgroud)

我想对此进行单元测试.理想情况下,单元测试意味着需要测试每个功能线.我不确定如何打开数据库连接,然后是否显示数据库的所有内容.我该如何测试这段代码?

此函数是简单CRUD应用程序的GET端点.代码在这里.

fis*_*ben 5

重构您的代码并将其分解为您将依赖项传递给的较小的可测试函数.还为依赖项创建接口以使测试更容易.

例如:

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
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以为依赖项创建模拟并在测试中使用它们:

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
}
Run Code Online (Sandbox Code Playgroud)

Open您可以在外面打开它并将其用于您的功能,而不是每次处理请求时调用.这样处理程序变得如此之小,不需要真正测试它:

func makeAllItemsHandler(db myDatabaseInterface) func(http.ResponseWriter, *http.Request) {
    return func(http.ResponseWriter, *http.Request) {
        items := findItems(db)
        json.NewEncoder(w).Encode(items)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,当您设置应用程序并将其传递给需要它的函数时,您可以一劳永逸地创建一个db,从而从函数中删除难以测试的代码.