为什么我们使用接口来模拟方法 Golang

Why we use interface for mocking methods Golang

刚接触Golang,一直在摸索,但不太清楚单元测试中的mocking。任何人都可以解释以下具体问题吗?

问题1:在Golang中编写单元测试,为什么我们需要有模拟方法的接口,为什么不只是struct?

问题2: 为什么我们在struct中注入接口(调用外部方法的地方)

使用结构 -

type GlobalData struct {}

var (
    GlobalObj = GlobalData{}
)

func (g GlobalData) GetGlobalData(a string) string{
    return a
}

有接口定义-

type GlobalInterface interface {
    GetGlobalData(a string) string
}

type GlobalData struct {}

var (
    GlobalObj = GlobalData{}
)

func (g GlobalData) GetGlobalData(a string) string{
    return a
}

谢谢

如果你在包用户中有类型的方法,比如说,例如。 包用户

type User struct {
 name string
}

func (u *User) GetUserProfile() UserProfile{}

现在在目录包中导入:

package catalog

import user

func getUserCatalog(user user.User) []catalog {
 user.GetUserProfile()
}

现在测试 getUserCatalog 方法有两种方法:

1. var getUserProfileFunc = user.GetUserProfile

使用这种方法 mock 可以在测试 运行 时轻松通过,例如:

getUserProfile = func() UserProfile { 
 return fakeUserProfile 
}

这是最简单的测试方法。

现在有另一种使用界面的方法,在包中用户添加一个界面,如

type UserInterface interface {
  GetUserProfile() UserProfile
}

如果用户包是一个您无法控制的库,则创建您自己的界面,键入并使用它。

在这种情况下,目录包中的测试将变成:

因为现在将从 UserInterface 类型而不是 UserType 调用方法,因此在测试时:

UserInterface = fakeUserStruct

并按照以下步骤操作

//1. define type of func to return 

type typeGetUserProfile func() UserProfile

//2. create a var to return

var mockedGetUserProfile typeGetUserProfile

//3. create a type

type FakeUser struct{}

//4. implement method interface

func (user *FakeUserStruct) GetUserProfile() UserProfile{
  return mockedGetUserProfile
 }

现在运行宁测试时:

mockerGetUserProfile = func() UserProfile {
  return fakeUserProfile
 }

有一个模拟库可以帮助创建用于模拟的样板代码。检查这个 https://github.com/stretchr/testify

还有很多其他模拟库,但我用过这个,真的很酷。

希望对您有所帮助。

如果没有请告诉我,我会给出一些示例代码并将其推送到 Github。

另请检查https://levelup.gitconnected.com/utilizing-the-power-of-interfaces-when-mocking-and-testing-external-apis-in-golang-1178b0db5a32

问题1:在Golang中编写单元测试,为什么我们需要有模拟方法的接口,为什么不只是struct?

回答:不是强制性的

问题2:为什么要在struct中注入接口(调用外部方法的地方)

回答:因为,它可以帮助您替换实际的函数调用(作为单元测试的一部分可能会触发一些超出范围的操作,例如 数据库调用some API call etc) 通过注入 MockStruct (这将实现与实际代码中相同的 interface )。 多态性 简单来说。

因此,您创建了一个 MockStruct 并为其定义了您自己的 mockMethods。作为多态性,你的单元测试选择 MockStruct 毫无怨言。调用实际数据库或 http 端点不属于 单元测试

仅供参考,我可以向您指出我的 github 代码库之一,我在其中编写了 small test case for a file。如您所见,我嘲笑了 :

  1. GuestCartHandler interface , that allowed me to not call the actual implementation
  2. 使用 "github.com/DATA-DOG/go-sqlmock" 包模拟 sql connection。这帮助我避免建立实际的 db client(因此,单元测试时不依赖数据库)

如果您从概念上理解了这个想法,或者您是否需要更多说明,请告诉我。