golang / mock

GoMock is a mocking framework for the Go programming language.
Apache License 2.0
9.26k stars 608 forks source link

Cannot install and run mockgen from the vendor directory #95

Closed sugarjig closed 6 years ago

sugarjig commented 6 years ago

We would like to "vendorize" mockgen in our project, in order to freeze the version we are using and prevent unexpected breakages. We already do this with gomock for the same reason. We use govendor for this.

We vendorize gomock with govendor fetch github.com/golang/mock/mockgen@v1.0.0. Then, we can install mockgen from the vendor/ directory using govendor install +vendor. However, when we try to run mockgen, we get the following output:

prog.go:11:2: cannot find package "github.com/golang/mock/mockgen/model" in any of:
        /usr/local/Cellar/go/1.8.3/libexec/src/github.com/golang/mock/mockgen/model (from $GOROOT)
        /<omitted>/go/src/github.com/golang/mock/mockgen/model (from $GOPATH)

This is obviously because the package github.com/golang/mock/mockgen/model is not at the mentioned locations, but under our vendor/ directory. One way to fix this is to run go get -u github.com/golang/mock/mockgen, which places the model package under $GOPATH. Another way is to run govendor get -u github.com/golang/mock/mockgen@v1.0.0, which is what we currently do. The advantage to "vendorizing" it as described above is that it centralizes the version management with the rest of our dependencies.

Why is there a runtime dependency on this model package? Shouldn't it be compiled into the mockgen binary? Is there any way to install mockgen from the vendor directory?

kaedys commented 6 years ago

Worth noting, why it has a runtime dependency (which isn't normally a thing for Go programs) is because mockgen actually creates a new program, using the built in template package, then compiles and runs it to generate the mock. It does this so it can actually import the package being mocked directly, allowing it to use the reflection package to get information about the types instead of having to parse the file (which runs into problems if the package being mocked imports and uses types from other packages). Reference: https://github.com/golang/mock/blob/master/mockgen/reflect.go#L118

It uses the mock/model package in this template function to access a number of helper functions that it uses to parse the reflection return. In theory, these functions could instead be written directly into the generated program, removing the dependency, but then the authors would lose the ability to compile-time verify that code and go test it.

Not sure if there's a clean and elegant solution to your use case, unfortunately.

mandazi commented 6 years ago

@sugarjig https://github.com/golang/mock/pull/28 was merged and I believe that fixes your issue here.

sugarjig commented 6 years ago

It looks like that PR was to add support for mocking vendored dependencies, whereas what we're looking for is "vendorizing" gomock. The idea is to pin gomock to a specific version. Using govendor get -u github.com/golang/mock/mockgen@v1.0.0 is currently working for us, though.

blind-oracle commented 6 years ago

Use https://github.com/twitchtv/retool

kaedys commented 6 years ago

A useful tool, @blind-oracle, but I don't think it will actually solve the problem, at least on its own. The issue here is that mockgen has a runtime dependency on one of its source files, so the only way to make it work with vendoring is to build the template reflection program inside the source tree that vendors gomock. This will require a change to the mockgen code itself, probably by allowing the user to specify a build location.

LasTshaMAN commented 6 years ago

Any updates on this issue ?

The thing is, when a project relies on "vendor" directory (which, I believe, most of them do) it can't use reflect mode for mockgen ...

And reflect mode is the recommended one, because in source mode you can't even mock embedded interface like io.Writer (as far as I know) ...

kaedys commented 6 years ago

The thing is, when a project relies on "vendor" directory (which, I believe, most of them do) it can't use reflect mode for mockgen ...

It can, actually, as of #28 and #99. The only thing that isn't currently possible (and what this ticket is about) is vendoring gomock itself and then using the vendored version to generate your mock code.

sugarjig commented 6 years ago

On the suggestion of @blind-oracle I gave retool a try, and it is working for us. We are able to check in a specific version of mockgen and use that by running retool do mockgen.

balshetzer commented 6 years ago

@sugarjig I recently changed mockgen to try to run inside the code tree. I realize that this problem is solved for you with retool but if you're willing to try your original method again and report back then I'd appreciate it.