-1

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.
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)
    }
}

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 :
mockgen -source main.go -aux_files o=otheri/otheri.go executed at the same level as the main.go
But my mockgen file is empty....
Does anyone has an idea ? My goal is to mock the interface o.Foo contains in main.go me without changing my architecture
I need to mock it to test it with unit tests. The architecture is like this because I follow clean architecture. Thanks for all

Kiki
  • 71
  • 8
  • 1
    There is no need to mock an interface. What are you actually trying to do and why? – Volker Apr 29 '22 at 09:05
  • Anything conforming to `o.Foo` (ie anything with an `Ask() error` method) will automatically work. That said, I'd recommend declaring interfaces in the package that use/require them, rather than along side the type that implements them. You're also using a `mockgen` generated type without the controller and you're not calling the constructor. The types are not what they seem – Elias Van Ootegem Apr 29 '22 at 09:16
  • My goal is to reproduce clean architecture, so the logic is controlled by the business_logic side. Here my main is the user_side and the `otheri` is the business_logic side. https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html – Kiki Apr 29 '22 at 09:37

1 Answers1

2

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

Ben Mathews
  • 2,939
  • 2
  • 19
  • 25
isavinof
  • 132
  • 5