如何在测试案例中模拟结构的方法调用

时间:2018-08-09 06:45:39

标签: unit-testing go mocking

这是该结构及其方法的示例代码

type A struct {}

func (a *A) perfom(string){
...
...
..
} 

然后我想从驻留在软件包外部的函数invoke()(示例代码)中调用该方法

var s := A{}
func invoke(url string){
   out := s.perfom(url)
   ...
   ...
} 

我想通过模拟A的invoke方法来编写函数perform的测试用例。

在Java中,我们有mockito,jmock框架来存根方法调用。

有什么办法,我们可以模拟结构的方法调用而无需在源代码中引入interfaces吗?

2 个答案:

答案 0 :(得分:4)

要模拟方法调用,您需要对结构进行模拟。

对于您提供的代码示例,我建议创建一个Performer接口来实现您的Perform调用。您的真实结构和模拟结构都将实现此接口。

我还建议您将结构作为参数传递给invoke函数,而不要使用全局变量。

这里是一个例子:

type Performer interface {
    perform()
}

type A struct {
}

func (a *A) perform() {
    fmt.Println("real method")
}

type AMock struct {
}

func (a *AMock) perform () {
    fmt.Println("mocked method")
}

func caller(p Performer) {
    p.perform()
}

在测试中,将模拟注入到您的invoke调用中。 在您的真实代码中,将真实结构注入您的invoke调用中。

使用https://godoc.org/github.com/stretchr/testify/mock之类的库,您甚至可以真正轻松地验证使用正确的参数,正确的次数调用您的方法,并控制模拟的行为。

答案 1 :(得分:1)

在运行测试之前,将Perfom方法分配给全局变量,然后使用模拟方法将其重新分配。

例如

51760447/a/a.go

package a

type A struct{}

func (a *A) Perfom(url string) (string, error) {
    return "real data", nil
}

51760447/caller.go

package caller

import "github.com/mrdulin/golang/src/stackoverflow/51760447/a"

var s = a.A{}
var (
    Perfom = s.Perfom
)

func Invoke(url string) string {
    out, _ := Perfom(url)
    return out
}

51760447/caller_test.go

package caller_test

import (
    "reflect"
    "testing"

    caller "github.com/mrdulin/golang/src/stackoverflow/51760447"
)

func TestInvoke(t *testing.T) {
    oPerfom := caller.Perfom
    perfomCallCount := 0
    caller.Perfom = func(url string) (string, error) {
        perfomCallCount++
        return "fake data", nil
    }
    defer func() {
        caller.Perfom = oPerfom
    }()
    got := caller.Invoke("localhost")
    want := "fake data"
    if !reflect.DeepEqual(got, want) {
        t.Errorf("should return fake data, got:%v, want: %v", got, want)
    }
    if !reflect.DeepEqual(perfomCallCount, 1) {
        t.Errorf("Perfom method should be called once, got:%d", perfomCallCount)
    }
}

单元测试结果:

=== RUN   TestInvoke
--- PASS: TestInvoke (0.00s)
PASS
coverage: 100.0% of statements
ok      github.com/mrdulin/golang/src/stackoverflow/51760447    0.033s

覆盖率报告:

enter image description here