如何避免模拟生成中的导入周期?

Rhi*_*rva 6 go

简单的例子。

我有包裹xxx。该软件包包含:

现在想象一下,我想为结构A和模拟依赖项B创建单元测试。为创建模拟,我正在使用模拟生成器。所有模拟都存储在公用的“ mocks”文件夹中。

问题在于生成的模拟对xxx包具有依赖性。这是因为接口B的SomeMethod具有参数xxx.C。

每当我尝试将我的模拟结构导入a_test.go时,都会由于循环导入问题而失败。xxx程序包在a_test.go中导入了模拟程序包。并且模拟程序包在我生成的模拟程序中导入xxx程序包。

我需要一个平和的建议,对此最好的解决方法是什么?也许我的方法不够习惯。您将模拟物存储在哪里?

fal*_*way 9

您需要将测试放在不同的包中。

a.go 正在打包中 xxx

a_test.go 正在打包中 xxx_test

a_mock.go 正在打包中 xxx_mock

通过这种方式a_test.go将取决于xxxxxx_mock,不会造成依赖循环。

另外,a.go并且a_test.go可以是相同的文件夹下,这样的:

xxx/
  - a.go
  - a_test.go
mock/
  - a_mock.go
Run Code Online (Sandbox Code Playgroud)

  • 我的评论仅针对第二个插图,其中您说“a.go”和“a_test.go”可以位于同一文件夹下(是的,我将该文件夹作为一个包读取,因为 go 编译器也将它们作为一个包读取。如果我尝试过将 `a_test.go` 放在不同的包但相同的目录中,那么它会在同一目录中抛出多个包错误)。 (2认同)

see*_*jyh 7

自从

  1. 界面
  2. 结构体
  3. 用户代码
  4. 用户代码的单元测试

都在同一个包中,该接口应被视为“包内”接口,对于其他包中的代码是不可见的。因此,该接口的模拟应该与接口本身位于同一包中。

结论:

  1. 界面
  2. 结构体
  3. 用户代码
  4. 用户代码的单元测试
  5. 模拟接口

将它们全部放在同一个包中。

因此,将gomock生成的mock代码放入与接口相同的包中,而不是“mock”包中。示例(Windows版本):

mockgen -source=.\foo\bar.go -destination=.\foo\bar_mock.go -package=foo
Run Code Online (Sandbox Code Playgroud)


Lan*_*ara 0

使用所有其他包从中导入的顶级包。把你的接口放在那里。

例如:

domain/
    interfaces.go
a/
    mock.go
b/
    mock.go
c/
    mock.go
Run Code Online (Sandbox Code Playgroud)

ab并且c应该从中导入,domain这样它们就不会相互依赖。您将使用鸭子类型来实现模拟中包的接口domain

这是使用您的示例的实际用例:

域/interfaces.go

type A interface {
    Foo()
}

type B interface {
    Bar() string
}

type C interface {
    Baz() string
}
Run Code Online (Sandbox Code Playgroud)

a/mock.go

type A struct {
    SomeField domain.B
}

// ...
Run Code Online (Sandbox Code Playgroud)

b/mock.go

type B struct {
    SomeMethod(c domain.C)
}

// ...
Run Code Online (Sandbox Code Playgroud)

c/mock.go

type C struct {}

// ...
Run Code Online (Sandbox Code Playgroud)

这应该可以很好地编译,因为所有模拟都从顶级domain包导入,并且它们都实现了各自的接口。