来自 golang 包的模拟方法

问题描述 投票:0回答:5

我一直无法找到从 golang 包中模拟方法的解决方案。

例如,我的项目有代码在 Os.Getwd() 返回错误时尝试恢复。我可以考虑为此进行单元测试的最简单方法是模拟 Os.Getwd() 方法以返回错误,并验证代码是否相应地工作。

我尝试使用testify,但似乎不可能。

有人有这方面的经验吗?

unit-testing go mocking testify
5个回答
3
投票

我自己的解决方案是将方法作为参数,这允许在测试时注入“模拟”。此外,创建一个导出的方法作为公共外观和一个未导出的方法用于测试。

示例:

    func Foo() int {        
            return foo(os.Getpid)
    }                       

    func foo(getpid func() int) int {
            return getpid()      
    } 

1
投票

我知道这有点晚了,但是,这是你可以做到的方法。

测试 DAL 或系统调用或包调用通常很困难。我解决这个问题的方法是将系统函数调用推到接口后面,然后模拟这些接口的函数。例如。

type SystemCalls interface {
 Getwd() error
}


type SystemCallsImplementation struct{
}
func (SystemCallsImplementation) Getwd() error{
 return  Os.Getwd() 
}

func MyFunc(sysCall SystemCalls) error{

sysCall.Getwd()
}

这样,您就可以注入对您的函数进行系统调用的接口。现在您可以轻松创建接口的模拟实现以进行测试。

喜欢

type MockSystemCallsImplementation struct{
err error
}
func (MockSystemCallsImplementation) Getwd() error{
return err  //this can be set to nil or some value in your test function
}

希望这能回答您的问题。


0
投票

看起来查看 os.Getwd 测试 可以为您提供一些如何测试代码的示例。查找函数

TestChdirAndGetwd
TestProgWideChdir

从阅读这些内容来看,测试似乎创建了临时文件夹。

因此,一种务实的方法是创建临时文件夹,就像上面提到的测试一样,然后破坏它们,这样

os.Getwd
就会抛出一个错误,让你在测试中捕捉到。

执行这些操作时要小心,因为它们可能会弄乱您的系统。我建议在轻量级容器或虚拟机中进行测试。


0
投票

这是 go 编译器的限制,google 开发人员不想允许任何钩子或猴子修补。如果单元测试对您很重要 - 那么您必须选择一种源代码中毒方法。所有这些方法如下:

  • 不能直接使用全局包。
  • 您必须创建方法的独立版本并对其进行测试。
  • 生产版本的方法包括隔离版本的方法和全局包。

但最好的解决方案是完全忽略 go 语言(如果可能的话)。


0
投票

@Pharaoh 上面的答案是最好的,特别是对于广泛的测试,因为它允许标准模拟提供的所有控制。

对于仅需要模拟少量方法的简单情况以及相当简单的情况,我使用以下方法,避免需要创建新接口并使用标准调用来实现该接口的包。

在测试实施中:

package myPackage

imports (...)

var (
    kill = syscall.Kill
    getCwd = os.GetCwd
)

测试代码中:

// restore golang methods from "poor man's mocks"
func restore() {
    kill = syscall.Kill
    getWd = os.GetWd
}

func TestMyFunc(t *testing.T) {
    defer restore()

    // successful case
    kill = func(p int, s syscall.Signal) error {
        return nil
    }
    getWd = func() (string, error) {
        return "mywd", nil
    }
    err := MyFunc()
    assert.NoError(t, err)

    // error case for GetCwd
    getCwd = func(path string) (string, error) {
        return "", errors.New("test error")
    }
    err := MyFunc()
    assert.ErrorContains(t, "test error")
}
© www.soinside.com 2019 - 2024. All rights reserved.