gpt4 book ai didi

unit-testing - 如何在 Go 中模拟包方法?

转载 作者:行者123 更新时间:2023-12-04 14:06:01 26 4
gpt4 key购买 nike

假设我有一个包含以下代码的包:

package paths

type FilePath struct {
PathA string
}

func (c FilePath) GetPathA() string {
if err := PathExists(PathA); err != nil {
return ""
}
return PathA + "foo"
}

func PathExists(p string) error {
// call os and file methods
return err
}
如何模拟 PathExists 依赖项来测试 FilePath?此外,方法 PathExists许多其他软件包也正在使用。 (我愿意接受重构以使其测试友好的建议,请记住以下几点)
我遇到过几种不同的方法,但对我来说,它们都不是直观或惯用的。
  • 有一个全局变量 PE := PathExists在包裹中;在 GetPathA , 拨打 err := PE(PathA)并在测试中覆盖 PE用模拟方法。
    问题:如果测试包类似于paths_test,我将不得不导出PE这也允许包的客户端覆盖它。
  • 制作 PathExists领域FilePath并模拟测试中的字段。
    问题:客户端在使用包时,必须初始化 PathExists字段,或者我提供形式为 NewFilePath(PathtA string) 的构造函数它为我初始化字段。在实际用例中有很多字段,因此这种方法也失败了。
  • 使用接口(interface)并将其嵌入到结构中。当客户端使用它时,使用实际方法进行初始化并进行测试模拟。
    type PathExistser interface{ 
    PathExists(p string) error
    }

    type FilePath struct{
    PathA string
    PathExister
    }

    type Actual struct{}

    func (a Actual) PathExists(p string) error {
    return PathExists(p)
    }
    问题:客户端再次需要提供接口(interface)的正确实现。

  • 我已经了解了一些与上述选项类似的方法,例如 make 方法 PathExists GetPathA 的参数等等。都有同样的顾虑。基本上,我不希望这个包的用户必须弄清楚什么应该是正确的输入参数以确保结构按预期工作。我也不希望用户覆盖行为 PathExists .
    这似乎是一个非常简单的问题,我似乎错过了关于 go testing 或 mocking 的一些非常基本的东西。任何帮助将不胜感激,谢谢。
    方法名称只是一个例子。现实中 GetPathAPathExists会更复杂。

    最佳答案

    从您的 1. 解决问题方法,您可以使用一个内部包,然后您将能够在 paths_test 中导入该包。但你的包裹的客户不会。

    package paths

    import (
    // ...
    "<your_module_path>/internal/osutil"
    )

    func PathExists(p string) error {
    return osutil.PathExists(p)
    }
    package osutil

    var PathExists = func(p string) error {
    // call os and file methods
    return err
    }

    // Use a mutex to make sure that if you have
    // multiple tests using mockPathExists and running
    // in parallel you avoid the possiblity of a data race.
    //
    // NOTE that the mutex is only useful if *all* of your tests
    // use MockPathExists. If only some do while others don't but
    // still directly or indirectly cause the paths.PathExists
    // function to be invoked then you still can run into a data
    // race problem.
    var mu sync.Mutex

    func MockPathExists(mock func(p string) error) (unmock func()) {
    mu.Lock()
    original := PathExists
    PathExists = mock
    return func() {
    PathExists = original
    mu.Unlock()
    }
    }
    package paths_test

    import (
    // ...
    "<your_module_path>/internal/osutil"
    )

    func TestPathExists(t *testing.T) {
    unmock := osutil.MockPathExists(myPathExistsMockImpl)
    defer unmock()
    // do your test
    }

    关于unit-testing - 如何在 Go 中模拟包方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68494658/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com