英文:
How to mock a file with interface imported from another file
问题
我尝试创建一个模拟文件,其中包含从另一个文件导入的接口。我尝试使用aux_files
和imports
,但是我没有成功得到一个正确的模拟文件。我觉得我漏掉了什么。
所以我有一个像这样的mockgen/main.go
文件:
package main
import (
"log"
o "mockgen/otheri"
)
type bar struct {
a o.Foo
}
func NewBar(a o.Foo) *bar {
return &bar{a}
}
func main() {
var t = NewBar(&o.FunctionStuct{})
if err := t.a.Ask(); err != nil {
log.Fatal(err)
}
}
而导入的接口在mockgen/otheri/otheri.go
文件中:
package otheri
import "log"
type Foo interface {
Ask() error
}
type FunctionStuct struct {
}
func (f *FunctionStuct) Ask() error {
log.Println("Hello")
return nil
}
我尝试的命令是:
mockgen -source main.go -aux_files o=otheri/otheri.go
在与main.go文件相同的级别上执行。
但是我的mockgen文件是空的...有人有什么想法吗?我的目标是在不改变我的架构的情况下模拟包含在main.go中的接口o.Foo
。我需要模拟它以便进行单元测试。这种架构是因为我遵循了清晰架构。谢谢大家。
英文:
<br>
I try to create a mock of a file with an interface imported from another file. I have try with aux_files
and imports
but I did non succeed to have a correct mock file. I think I'm missing something.
<br>
So I have a mockgen/main.go
like this :
package main
import (
"log"
o "mockgen/otheri"
)
type bar struct {
a o.Foo
}
func NewBar(a o.Foo) *bar {
return &bar{a}
}
func main() {
var t = NewBar(&o.FunctionStuct{})
if err := t.a.Ask(); err != nil {
log.Fatal(err)
}
}
<br>
And the interface imported is in mockgen/otheri/otheri.go
:
package otheri
import "log"
type Foo interface {
Ask() error
}
type FunctionStuct struct {
}
func (f *FunctionStuct) Ask() error {
log.Println("Hello")
return nil
}
The command I tried is : <br>
mockgen -source main.go -aux_files o=otheri/otheri.go
executed at the same level as the main.go
<br>
But my mockgen file is empty....<br>
Does anyone has an idea ? My goal is to mock the interface o.Foo
contains in main.go me without changing my architecture<br>
I need to mock it to test it with unit tests.
The architecture is like this because I follow clean architecture.
Thanks for all
答案1
得分: 2
你只能为接口生成模拟。所以,在你的例子中,你应该运行mockgen
命令来针对文件mockgen/otheri/otheri.go
生成模拟,因为目标接口在那里定义。
但正如Elias Van Ootegem指出的那样,将一个与其相符的结构体放在接口中是一种不好的做法。你应该将接口和实现分开。所以,应该像这样修改:
文件/bar/bar.go
package bar
import (
"log"
)
type Foo interface {
Ask() error
}
type bar struct {
foo Foo
}
func NewBar(a Foo) *bar {
return &bar{a}
}
func (b *bar) Ask() {
if err := b.foo.Ask(); err != nil {
log.Fatal(err)
}
}
文件otheri/otheri.go
package otheri
import "log"
type FunctionStruct struct {
}
func (f *FunctionStruct) Ask() error {
log.Println("Hello")
return nil
}
文件main.go
package main
import (
"bar"
"otheri"
)
func main() {
fs := &otheri.FunctionStruct{}
b := bar.NewBar(fs)
b.Ask()
}
然后使用mockgen
命令生成模拟:mockgen -source=bar/bar.go -destination=bar/mock/foo_mock.go Foo
此外,遵循Effective Go中描述的规则,最好的方法是隐藏FunctionStruct
类型:
如果一个类型只存在于实现一个接口,并且除了该接口之外不会有其他导出方法,那么无需导出该类型本身。
因此,最终的解决方案是将接口移到一个单独的包中:
文件/foo/foo.go
package foo
type Foo interface {
Ask() error
}
文件/bar/bar.go
package bar
import (
"log"
"foo"
)
type bar struct {
foo foo.Foo
}
func NewBar(a foo.Foo) *bar {
return &bar{a}
}
func (b *bar) Ask() {
if err := b.foo.Ask(); err != nil {
log.Fatal(err)
}
}
文件otheri/otheri.go
package otheri
import (
"log"
"foo"
)
func New() foo.Foo {
return &functionStruct{}
}
type functionStruct struct {
}
func (f *functionStruct) Ask() error {
log.Println("Hello")
return nil
}
文件main.go
package main
import (
"bar"
"otheri"
)
func main() {
b := bar.NewBar(otheri.New())
b.Ask()
}
然后使用mockgen
命令生成模拟:mockgen -source=foo/foo.go -destination=foo/mock/foo_mock.go Foo
英文:
You can generate mocks only for interfaces. So, in your example you should run mockgen for file mockgen/otheri/otheri.go
because target interface presented where.
But as Elias Van Ootegem pointed out, it's a bad practice to have an interface with the struct which conforming it. You should separate interface and implementation.
So, it should be something like:
File /bar/bar.go
package bar
import (
"log"
)
type Foo interface {
Ask() error
}
type bar struct {
foo Foo
}
func NewBar(a Foo) *bar {
return &bar{a}
}
func (b *bar) Ask() {
if err := b.foo.Ask(); err != nil {
log.Fatal(err)
}
}
File otheri/otheri.go
package otheri
import "log"
type FunctionStruct struct {
}
func (f *FunctionStruct) Ask() error {
log.Println("Hello")
return nil
}
File main.go
package main
import (
"bar"
"otheri"
)
func main() {
fs := &otheri.FunctionStruct{}
b := bar.NewBar(fs)
b.Ask()
}
And generate a mock mockgen -source=bar/bar.go -destination=bar/mock/foo_mock.go Foo
Furthermore, follow the rules described in effective go the best way to use your FunctionStruct
- hide the type in the package:
> If a type exists only to implement an interface and will never have exported methods beyond that interface, there is no need to export the type itself
So, the final solution will move interface to a separate package:
File /foo/foo.go
package foo
type Foo interface {
Ask() error
}
File /bar/bar.go
package bar
import (
"log"
"foo"
)
type bar struct {
foo foo.Foo
}
func NewBar(a foo.Foo) *bar {
return &bar{a}
}
func (b *bar) Ask() {
if err := b.foo.Ask(); err != nil {
log.Fatal(err)
}
}
File otheri/otheri.go
package otheri
import (
"log"
"foo"
)
func New() foo.Foo {
return &functionStruct{}
}
type functionStruct struct {
}
func (f *functionStruct) Ask() error {
log.Println("Hello")
return nil
}
File main.go
package main
import (
"bar"
"otheri"
)
func main() {
b := bar.NewBar(otheri.New())
b.Ask()
}
And mockgen: mockgen -source=foo/foo.go -destination=foo/mock/foo_mock.go Foo
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论