dqq3623 2018-03-16 18:35
浏览 110
已采纳

在Golang中伪造数据库方法

I'm trying to create a unit test for the following function that is making database calls internally using Postgres driver:

type DBer interface {
    Exec(query string, args ...interface{}) (sql.Result, error)
    Query(query string, args ...interface{}) (interface{}, error)
    QueryRow(query string, args ...interface{}) *sql.Row
    Prepare(query string) (*sql.Stmt, error)
}

type AppInfoCtrl struct {
    DB DBer
}

type Rower interface {
    Next() bool
    Close() error
    Scan(...interface{}) error
}

func parseRows(rows Rower, infos []AppInfo) ([]AppInfo, error) {
    defer rows.Close()
    for rows.Next() {
        var i AppInfo
        if err := rows.Scan(&i.Id, &i.Platform); err != nil {
            return nil, err
        }
        infos = append(infos, i)
    }
    return infos, nil
}

func (a *AppInfoCtrl) List() ([]AppInfo, error) {
    query := "select id, platform from appinfo where deleted = false"
    rows, err := a.DB.Query(query)
    if err != nil {
        return nil, err
    }

    appInfos := []AppInfo{}
    parseRows(rows, appInfos)

    return appInfos, nil
}

And my test looks like this:

func (f *FakeDB) Query(query string, args ...interface{}) (*sql.Rows, error) {
    fmt.Println(query)
    var rows *sql.Rows
    return rows, nil
}

However, after running this I get the following compilation error:

appinfo/controller.go:68:11: cannot use rows (type interface {}) as type Rower in argument to parseRows:
        interface {} does not implement Rower (missing Close method)

When I look at the source code, sql.Rows does implement Close():

https://golang.org/pkg/database/sql/#Rows.Close

Any idea what I need to do here? Am I even taking the right approach to test List() here? I'm not particularly picky about testing parseRows() as it only contains calls to db.Rows, but I need to at least test List here.

  • 写回答

1条回答 默认 最新

  • doujiu3768 2018-03-16 18:46
    关注

    The problem is that DBer.Query returns a generic interface{}, which the compiler cannot assume has any methods at all:

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

    Meaning, unless you use a type assertion, you cannot call any methods on the returned value. Perhaps it should instead return (Rower, error)?

    The compiler, in effect, sees this:

    rows, err := a.DB.Query(query)
    

    rows is a interface{}. It could be anything. It could be an int. It cannot assume it has any methods at all. So when you pass it to parseRows:

    parseRows(rows, appInfos)
    

    Defined as:

    func parseRows(rows Rower, infos []AppInfo) ([]AppInfo, error)
    

    Well, it takes a Rower, but you're passing an interface{}, which is not guaranteed to implement Rower. Hence the compiler error you're getting:

    interface {} does not implement Rower (missing Close method)
    

    It has nothing to do with the underlying value, but rather the type of the variable. The variable is of type interface{}, which has no methods, and therefor does not implement Rower.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 高价求中通快递查询接口
  • ¥15 解决一个加好友限制问题 或者有好的方案
  • ¥15 关于#java#的问题,请各位专家解答!
  • ¥15 急matlab编程仿真二阶震荡系统
  • ¥20 TEC-9的数据通路实验
  • ¥15 ue5 .3之前好好的现在只要是激活关卡就会崩溃
  • ¥50 MATLAB实现圆柱体容器内球形颗粒堆积
  • ¥15 python如何将动态的多个子列表,拼接后进行集合的交集
  • ¥20 vitis-ai量化基于pytorch框架下的yolov5模型
  • ¥15 如何实现H5在QQ平台上的二次分享卡片效果?