如何使用从另一个文件导入的接口来模拟一个文件?

huangapple go评论81阅读模式
英文:

How to mock a file with interface imported from another file

问题

我尝试创建一个模拟文件,其中包含从另一个文件导入的接口。我尝试使用aux_filesimports,但是我没有成功得到一个正确的模拟文件。我觉得我漏掉了什么。

所以我有一个像这样的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 (
	&quot;log&quot;
	o &quot;mockgen/otheri&quot;
)

type bar struct {
	a o.Foo
}

func NewBar(a o.Foo) *bar {
	return &amp;bar{a}
}

func main() {
	var t = NewBar(&amp;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 &quot;log&quot;

type Foo interface {
	Ask() error
}

type FunctionStuct struct {
}

func (f *FunctionStuct) Ask() error {
	log.Println(&quot;Hello&quot;)
	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 (
	&quot;log&quot;
)

type Foo interface {
	Ask() error
}

type bar struct {
	foo Foo
}

func NewBar(a Foo) *bar {
	return &amp;bar{a}
}

func (b *bar) Ask() {
	if err := b.foo.Ask(); err != nil {
		log.Fatal(err)
	}
}

File otheri/otheri.go

package otheri

import &quot;log&quot;

type FunctionStruct struct {
}

func (f *FunctionStruct) Ask() error {
	log.Println(&quot;Hello&quot;)
	return nil
}

File main.go

package main

import (
	&quot;bar&quot;
	&quot;otheri&quot;
)

func main() {
	fs := &amp;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 (
	&quot;log&quot;
    &quot;foo&quot;
)

type bar struct {
	foo foo.Foo
}

func NewBar(a foo.Foo) *bar {
	return &amp;bar{a}
}

func (b *bar) Ask() {
	if err := b.foo.Ask(); err != nil {
		log.Fatal(err)
	}
}

File otheri/otheri.go

package otheri

import ( 
   &quot;log&quot;
   &quot;foo&quot;
)

func New() foo.Foo {
    return &amp;functionStruct{}
}

type functionStruct struct {
}

func (f *functionStruct) Ask() error {
	log.Println(&quot;Hello&quot;)
	return nil
}

File main.go

package main

import (
	&quot;bar&quot;
	&quot;otheri&quot;
)

func main() {
	b := bar.NewBar(otheri.New())
	b.Ask()
}

And mockgen: mockgen -source=foo/foo.go -destination=foo/mock/foo_mock.go Foo

huangapple
  • 本文由 发表于 2022年4月29日 16:15:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/72054824.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定