gojuno / minimock

Powerful mock generation tool for Go programming language
MIT License
632 stars 38 forks source link

Mocks aren't generated for type aliases #106

Closed Wani4ka closed 1 month ago

Wani4ka commented 4 months ago

Due to AST interpreting interface aliases as aliases, and not as interfaces, minimock skips interface aliases and doesn't generate mocks for them.

For testing it out I used the latest version of minimock cloned directly from this repository.

Here are the steps to reproduce:

  1. Create a file, for example, ./example/types.go
  2. Fill it with the following contents:
    
    package example

import "io"

type Sampler interface { Sample() }

type Sampler2 Sampler type Sampler3 = Sampler type ReaderAlias io.Reader type ReadWriteSeekCloser interface { io.ReadWriteCloser io.Seeker }

3. Run generation command: `minimock -i "./example.*"`

I expect all five interfaces to be generated, but only the first one and the last one is generated, which we can see from the command output:
```sh
$ go run ./cmd/minimock -i "./example.*"
minimock: ./sampler_mock_test.go
minimock: ./read_write_seek_closer_mock_test.go
zcolleen commented 3 months ago

Hi! Thanks for raising issue, but imo i dont see it as a minimock issue. Minimock is defined to generate mocks from interfaces, not from interface aliases. I dont see where such behaviour would be useful

hexdigest commented 3 months ago

@zcolleen the inconvenience can be demonstrated by this case: type ReaderAlias io.Reader

@Wani4ka uses a shortcut to generate mocks for all interfaces from a certain package: go run ./cmd/minimock -i "./example.*" but this shortcut doesn't work for the ReaderAlias that refers to an interface from another package, so instead of running minimock just once, users have to run it multiple times in such (rare) cases.

A couple of workarounds that I can suggest:

  1. As I mentioned above, you can always generate a mock for the aliased type not the alias type itself, e.g. io.Reader. This will require to run minimock twice though
  2. Instead of defining an alias type, you can define an interface type and embed the interface type that you want to refer to:
    type ReaderAlias interface {
       io.Reader
    }

    for the interface types this should not make a difference in most cases.

I'm not sure that this makes any sense:

type Sampler2 Sampler
type Sampler3 = Sampler

But this totally makes sense to me:

type MyReaderAlias = io.Reader
type MyReaderType io.Reader

I think type aliases are more important issue here because despite the fact that interface types themselves are interchangeable, the derived container types like []InterfaceType or map[something]InterfaceTypes are not.

kavu commented 3 months ago

@zcolleen Hi! Long time no see. Actually we have such an isssue with our RTC Client (if you remember what is it :D) — we have private interfaces for our own needs and we have type alias for it and it is user facing public type alias. So here we are. Mocks are generated based on internal/ paths.

zcolleen commented 3 months ago

@kavu hey! Glad to hear from you. I see now that this feature is highly requested and we will definitely think of implementing this feature (although i don't quiet remember the mocking issue with RTC Client). The only consern that i have is that we will change behaviour by default, which can result in unexpected manner for somebody. May be we should add this behaviour as an optional flag? WDYT guys?

zcolleen commented 3 months ago

Hey guys, opened pr https://github.com/gojuno/minimock/pull/109 for this feature

zcolleen commented 1 month ago

feauture is available in v3.3.14 release