假设我有这个代码,我想为Foo()创建一个测试

重要的部分,它Foo拨打Bar

package main

type MyInterface interface {
    Foo() error
    Bar() error
}

type MyStruct struct {
}

func NewMyStruct() MyInterface{
    return &MyStruct{}
}

func (m *MyStruct) Foo() error {
    // do something
    m.Bar()
    // do something else
    return nil
}

func (m *MyStruct) Bar() error {
    // do something
    return nil
}

是否可以为此创建一个测试,使我可以在运行foo之前模拟Bar的行为?还是我做了一些根本错误的事情?

我可以看出,如果我让Bar进入它自己的服务,我会这样嘲笑它,但这也感觉不对劲.

任何关于文档的见解或链接都会很棒.

推荐答案

您应该能够通过几个更改来实现所需的功能.首先,让我介绍代码,然后我将向您介绍所有相关的更改.

main.go file

package main

type MyInterface interface {
    Foo() error
    Bar() error
}

type MyStruct struct {
    DS MyInterface
}

// here you've to depend upon an interface and return a pointer to a struct
func NewMyStruct(ds MyInterface) *MyStruct {
    return &MyStruct{
        DS: ds,
    }
}

func (m *MyStruct) Foo() error {
    // do something
    m.DS.Bar()
    // do something else
    return nil
}

func (m *MyStruct) Bar() error {
    // do something
    return nil
}

func main() {}

在这里,我更改了几项内容,以便能够成功地模拟我们的依赖项.让我扼要地回顾一下:

  1. MyStruct具有类型MyInterface的依赖项
  2. 函数NewMyStruct接受该接口作为参数,并返回指向MyStruct struct 的指针
  3. Foo方法中,我们将依赖指针接收器类型实例的DS字段

现在,让我们切换到测试文件.

main_test.go file

package main

import (
    "testing"

    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

// 1. declare mock
type myStructMock struct {
    mock.Mock
}

// 2. implement the interface
func (m *myStructMock) Foo() error {
    args := m.Called()
    return args.Error(0)
}

func (m *myStructMock) Bar() error {
    args := m.Called()
    return args.Error(0)
}

func TestFoo(t *testing.T) {
    // 3. instantiate/setup mock
    myStructMock := new(myStructMock)
    myStructMock.On("Bar").Return(nil).Times(1)

    sut := NewMyStruct(myStructMock)
    err := sut.Foo()

    // 4. check that all expectations were met on the mock
    assert.Nil(t, err)
    assert.True(t, myStructMock.AssertExpectations(t))
}

在这里,我发现最好在代码中添加注释,为您提供所发生的事情的时间顺序.其 idea 是,测试的真实系统(例如,sut变量)依赖于模拟而不是实际实现.多亏了方法Times,我们才能确保调用Bar方法一次.

I always used this approach when it comes to testing production code and I find it pretty flexible and amazing!
Let me know if this helps you or if you still need something else, thanks!

Go相关问答推荐

获取作为类型参数传递给方法接收方中的类型参数的切片的基础类型

关于如何使用 Service Weaver 设置多个不同侦听器的问题

go中跨域自定义验证的问题

通过 Terraform 中的 MapNestedAtribute 进行迭代

Golang text/template中的startswith函数 - 入门教程

使用Cookie身份验证的Gorilla Golang Websocket优化

是否可以在调试期间在 VSCode 中预览 github.com/shopspring/decimal 值?

判断一个区域内的纬度/经度点

使用模拟在 golang 中测试我的界面.专门测试调用同级函数的 1 个函数

如何模仿联合类型

Golang 构建多平台问题

从动态输入中提取字符串,其中部分字符串可能不存在

Golang模板无法访问embedFS中的文件

在 Go 中读取数字行

函数调用中的类型参数panic

如何排除溢出矩阵的坐标

Golang API 的 HTTPS

Go/Golang:如何从 big.Float 中提取最低有效数字?

如何断言类型是指向golang中接口的指针

Gorilla/Mux 和 Websocket 竞赛条件,这安全吗?