在golang中通过接口进行模拟

huangapple go评论77阅读模式
英文:

function Mocking through Interface in golang

问题

我正在尝试编写一个单元测试代码,该代码有三个级别的函数调用,如下所示:

主函数调用函数A(),然后函数A根据某些条件调用函数B()和C(),函数B调用函数E()和F(),而函数C在某些条件下调用函数G()和H()。
我已经开发了上述类似的代码,现在我想为函数B的函数E()和F()以及函数C的函数G()和H()进行模拟。请建议我如何使用接口来实现这一点。

英文:

I am trying to write a unit test code form following code which has 3 level of function calling as below:

The main function calls function A() and then function A calls function B() and C() depending upon some condition and function B calls function E() and F(), whereas function C calls function G() and H() on some condition.
The above like the code I have developed, Here I want to mock function E() and F() for function B, and G() and H() for function C. Please suggest me how to do it using interface.

答案1

得分: 1

抽象函数类型

你可以使用依赖注入而不是使用接口来实现:

import (
    "fmt"
    "math"
)

type a func(float64) float64

func A(arg float64) float64 {
    return math.Pow(arg, 2)
}

func mock(arg float64) float64 {
    return math.Sqrt(arg)
}

func b(function a, arg float64) float64 {
    return function(arg)
}

func main() {
    fmt.Println(b(A, 2))
    fmt.Println(b(mock, 2))
}

Go中的函数是一等公民

> 在编程语言设计中,给定编程语言中的一等公民(也称为类型、对象、实体或值)是支持其他实体通常可用的所有操作的实体。

这意味着你可以将函数作为参数传递,当然你也可以声明一个基于函数的具体接口类型 (不要与 interface 类型混淆)

接口方法

你可以使用函数进行组合:

import (
    "fmt"
    "math"
)

// 声明一个带有依赖的接口类型
type HGer interface {
    H(float64) float64
    G(float64) float64
}

// 声明一个带有嵌入接口的依赖类型
type Dependent struct {
    HGer
}

func (d *Dependent) B(arg float64) float64 {
    return d.H(arg) * d.G(arg)
}

// 为实际程序实现接口
type ImplHGer struct{}

func (i *ImplHGer) H(arg float64) float64 {
    return math.Pow(arg, 2)
}

func (i *ImplHGer) G(arg float64) float64 {
    return math.Sqrt(arg)
}

// 为依赖的模拟实现接口
type MockHGer struct{}

func (i *MockHGer) H(arg float64) float64 {
    return float64(0)
}

func (i *MockHGer) G(arg float64) float64 {
    return float64(0)
}

func main() {
    // 使用真实实现
    a := Dependent{new(ImplHGer)}
    // 使用模拟实现
    b := Dependent{new(MockHGer)}
    fmt.Println(a.B(8)) // 181.01933598375618
    fmt.Println(b.B(8)) // 0
}

嵌入

> 在结构体中包含一个匿名字段被称为嵌入。在这种情况下,Discount 类型被嵌入到 PremiumDiscount 类型中。所有 Discount 的方法都可以立即在 PremiumDiscount 类型上使用。此外,这些方法可以被隐藏。

可以将接口嵌入到结构体中,以扩展其行为或更具体地说,声明抽象依赖。

英文:

Abstract function type

You can do it with dependency injection not using interfaces:

import (
    "fmt"
	"math"
)

type a func(float64) float64

func A(arg float64) float64 {
    return math.Pow(arg, 2)
}

func mock(arg float64) float64 {
    return math.Sqrt(arg)
}

func b(function a, arg float64) float64 {
    return function(arg)
}

func main() {
    fmt.Println(b(A, 2))
	fmt.Println(b(mock, 2))
}

Function is first class citizen in Go

> In programming language design, a first-class citizen (also type, object, entity, or value) in a given programming language is an entity which supports all the operations generally available to other entities.

It means you can pass function as argument among other possibilities. And of course you can declare an abstract type based on function with concrete interface (Don't confuse with interface type)

Interface approach

You can make compositions using your functions

import (
	"fmt"
    "math"
)

// Declare an interface type with dependencies
type HGer interface {
    H(float64) float64
	G(float64) float64
}

// Declare a dependent type with embedded interface
type Dependent struct {
    HGer
}

func (d *Dependent) B(arg float64) float64 {
    return d.H(arg) * d.G(arg)
}

// Implement the interface for an actual program
type ImplHGer struct{}

func (i *ImplHGer) H(arg float64) float64 {
    return math.Pow(arg, 2)
}

func (i *ImplHGer) G(arg float64) float64 {
    return math.Sqrt(arg)
}

// Implement the interface for mock of dependencies
type MockHGer struct{}

func (i *MockHGer) H(arg float64) float64 {
    return float64(0)
}

func (i *MockHGer) G(arg float64) float64 {
    return float64(0)
}

func main() {
    // Use real implementation
    a := Dependent{new(ImplHGer)}
    // Use the mock
	b := Dependent{new(MockHGer)}
    fmt.Println(a.B(8)) // 181.01933598375618
	fmt.Println(b.B(8)) // 0
}

Embedding

> Including an anonymous field in a struct is known as embedding. In this case the Discount type is embedded in the PremiumDiscount type. All the methods of Discount are instantly available on the PremiumDiscount type. Furthermore those same methods can be hidden

It is possible to embed interface to struct to extend it's behavior or to be more specific - declare abstract dependency.

huangapple
  • 本文由 发表于 2017年4月14日 17:14:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/43408646.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定