如何在Golang中模拟函数 [英] How to mock functions in golang

查看:67
本文介绍了如何在Golang中模拟函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have written a simple package, which basically consists of a lot of getter functions. Each file in this package corresponds to a service, so for instance the product file, contains functions relating to the product service/db, order file to order service etc. Each function takes as parameters a db resource to the underlying db, and parameters for the sql, eg. productid, name, orderid. Each of the functions returns a struct (eg. Order, product) or an error:

// 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) {
   ...
}

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

The problem is that I'm not able to mock these functions from my main package. What I really like to do, is to rewrite the package, so I somehow can pass to function to a type instead. But I'm not sure how to do this. Especially not when the functions take different input parameters and return different structs. Is there a way to do this?

推荐答案

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

In Go you cannot mock a function declaration, same with method declarations on a concrete type, you cannot mock those.

例如:

func F()

func (T) M()

FM在Go中不可模拟.

F and M are not mockable in Go.

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

However you can mock function values, whether they are variables, fields on a struct, or parameters passed to other functions.

例如:

var Fn = func() { ... }

type S struct {
    Fn func()
}

func F(Fn func())

在所有三种情况下,

Fn都是可模拟的.

Fn in all three cases is mockable.

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

The other thing that you can mock in Go, and the prefered option most of the time, is an 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类型的值.

Now any piece of code that depends on ProductRepository can be passed a value of type ProductStore when you're in "normal mode" and a value of type ProductRepositoryMock when you're testing.

使用interface s的另一个选项,它允许您保持主要的功能不变,即定义一个模仿*sql.DB方法的接口,然后使用该接口类型作为要使用的类型.传递给您的函数,实现该接口的模拟版本,并在测试期间使用它.

Another option using interfaces, which allows you to keep your functions mostly unchaged is to define an interface that mimics the methods of *sql.DB then use that interface type as the type to be passed to your functions, implement a mock version of that interface and use that during testing.

例如:

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) {
   ...
}

DB参数现在是可模拟的.

DB parameter to GetProductByName is now mockable.

这篇关于如何在Golang中模拟函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆