Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Mockgen can't handle anonymous struct type #153

Open
ChuntaoLu opened this issue Feb 16, 2018 · 4 comments · May be fixed by #701
Open

Mockgen can't handle anonymous struct type #153

ChuntaoLu opened this issue Feb 16, 2018 · 4 comments · May be fixed by #701

Comments

@ChuntaoLu
Copy link
Contributor

Mockgen can't generate mocks for interfaces whose method param or return types are unnamed non-empty structs. For example:

Suppose I have a foo.go file whose package import path is foo:

package foo

type Client interface {
	Get() struct{ x int }
}

Running source mode mockgen -source=foo/foo.go gives

 failed parsing returns: foo/foo.go:4:8: can't handle non-empty unnamed struct types

Running reflect mode mockgen foo Client gives

Reflection: can't yet turn struct { x int } (struct) into a model.Type
@codyoss
Copy link
Member

codyoss commented Oct 18, 2019

@ChuntaoLu is this a common pattern you use? I had never seen an anonymous struct returned until just now 😸

@alvinmatias69
Copy link

@codyoss for me it's commonly found in legacy apps. Where the function arguments or return type is an anonymous struct

@bjohnson-va
Copy link

I'm actually warming up to this pattern when the opportunity arises.

Consider this example, where I have some low level implementation of a thing:

package lowlevel 

type LowLevelThing struct {
}

type LowLevelData struct {
  ID string
  Value int
}

func (l LowLevelThing) GetData() LowLevelData {
  ... the implementation ...
}

And now I have some high level module that wants to use the behaviour of the LowLevelThing. But, following the Dependency Inversion principle we're going to define our own interface so we're not coupled to the implementation.

package highlevel

// Look at me, I'm doing dependency inversion so I don't need to know about the implementation!
type Dependency interface {
  GetData() lowlevel.LowLevelData // <--- Shoot! Now I know about the implementation!
}

type HighLevelThing struct {
   dependency Dependency 
}

To avoid this problem, LowLevelData could just as easily return an anonymous struct with primitives:

func (l LowLevelThing) GetData() struct {
  ID string
  Value int
} {
  ... the implementation ...
}

And now the high level module doesn't need to know about the implementation.

//
// Look at me, I'm doing dependency inversion so I don't need to know about the implementation!
type Dependency interface {
  GetData() struct { // <-- And I mean it this time!
    ID string
    Value int
  }
} 

A struct is preferable over multiple return values, especially when there are multiple of the same type:

type Dependency {
  GetData() (string, string, string, string) <-- 🤔 which one was foo, again? Guess I'll go look at the implementation.
}

@bjohnson-va
Copy link

As a workaround, you can temporarily add a named struct to your implementation and update it to return that named struct before running code gen. Then undo those changes and manually update the mock to return anonymous structs.

Obviously not ideal, but a workaround nonetheless if you don't re-gen often.

bjohnson-va added a commit to bjohnson-va/mock that referenced this issue Apr 11, 2023
@bjohnson-va bjohnson-va linked a pull request Apr 11, 2023 that will close this issue
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants