繁体   English   中英

如何在Golang中模拟函数

[英]How to mock functions in golang

我编写了一个简单的程序包,该程序包基本上包含许多getter函数。 此软件包中的每个文件都对应一个服务,例如产品文件,包含与产品服务/数据库,订购文件到订购服务等相关的功能。每个功能都将基础数据库的db资源和参数用作参数。的SQL,例如。 产品编号,名称,订单编号。 每个函数都返回一个结构(例如,订单,产品)或错误:

// product.go

package lib

type Product struct {
   ID int
   Name string
   Price float
}

func GetProductById(DB *sql.DB, ID int) (p Product, err error) {
   q := "SELECT * FROM product WHERE id = " + ID
   ...
}

func GetProductByName(DB *sql.DB, name string) (p Product, err error) {
   ...
}

// order.go

package lib

type Order struct {
   ID int
   Date string
   Items []items
}

func GetOrderById(DB *sql.DB, ID int) (o Order, err error) {
   ...
}

问题是我无法从主程序包中模拟这些功能。 我真正想做的是重写程序包,因此我可以以某种方式将函数传递给类型。 但是我不确定该怎么做。 特别是当函数采用不同的输入参数并返回不同的结构时,尤其如此。 有没有办法做到这一点?

在Go中,您不能模拟函数声明,与对具体类型的方法声明相同,也不能模拟那些函数声明。

例如:

func F()

func (T) M()

FM在Go中不可模拟。


但是,您可以模拟函数值,无论它们是变量,结构上的字段还是传递给其他函数的参数。

例如:

var Fn = func() { ... }

type S struct {
    Fn func()
}

func F(Fn func())

在所有这三种情况下, Fn都是可模拟的。


您可以在Go中模拟的另一件事是大多数情况下首选的选项,它是interface

例如:

type ProductRepository interface {
    GetProductById(DB *sql.DB, ID int) (p Product, err error)
}

// the real implementater of the interface
type ProductStore struct{}

func (ProductStore) GetProductById(DB *sql.DB, ID int) (p Product, err error) {
    q := "SELECT * FROM product WHERE id = " + ID
    // ...
}

// the mock implementer
type ProductRepositoryMock struct {}

func (ProductRepositoryMock) GetProductById(DB *sql.DB, ID int) (p Product, err error) {
    // ...
}

现在,当您处于“正常模式”时,可以将依赖于ProductRepository任何代码段传递给ProductStore类型的值,而在进行测试时,可以传递给类型ProductRepositoryMock的值。


使用interface s的另一种选择,它允许您使函数大部分保持不变:定义一个模仿*sql.DB方法的接口,然后使用该接口类型作为要传递给函数的类型,实现该接口的模拟版本界面,并在测试过程中使用它。

例如:

type DBIface interface {
    Query(query string, args ...interface{}) (*sql.Rows, error)
    // ...
    // It's enough to implement only those methods that
    // the functions that depend on DBIface actually use.
    // If none of your functions ever calls SetConnMaxLifetime
    // you don't need to declare that method on the DBIface type.
}

type DBMock struct {}

func (DBMock) Query(query string, args ...interface{}) (*sql.Rows, error) {
    // ...
}

func GetProductByName(DB DBIface, name string) (p Product, err error) {
   ...
}

GetProductByName DB参数现在是可模拟的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM