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

在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 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?