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.

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

报告相同问题?

悬赏问题

  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了