Coder Social home page Coder Social logo

moq's Introduction

moq logo build Go Report Card

Interface mocking tool for go generate.

What is Moq?

Moq is a tool that generates a struct from any interface. The struct can be used in test code as a mock of the interface.

Preview

above: Moq generates the code on the right.

You can read more in the Meet Moq blog post.

Installing

To start using latest released version of Moq, just run:

$ go install github.com/matryer/moq@latest

Note that Go 1.18+ is needed for installing from source. For using Moq with older Go versions, use the pre-built binaries published with Moq releases.

Usage

moq [flags] source-dir interface [interface2 [interface3 [...]]]
  -fmt string
    	go pretty-printer: gofmt, goimports or noop (default gofmt)
  -out string
    	output file (default stdout)
  -pkg string
    	package name (default will infer)
  -rm
    	first remove output file, if it exists
  -skip-ensure
    	suppress mock implementation check, avoid import cycle if mocks generated outside of the tested package
  -stub
    	return zero values when no mock implementation is provided, do not panic
  -version
    	show the version for moq
  -with-resets
    	generate functions to facilitate resetting calls made to a mock

Specifying an alias for the mock is also supported with the format 'interface:alias'

Ex: moq -pkg different . MyInterface:MyMock

NOTE: source-dir is the directory where the source code (definition) of the target interface is located. It needs to be a path to a directory and not the import statement for a Go package.

In a command line:

$ moq -out mocks_test.go . MyInterface

In code (for go generate):

package my

//go:generate moq -out myinterface_moq_test.go . MyInterface

type MyInterface interface {
	Method1() error
	Method2(i int)
}

Then run go generate for your package.

How to use it

Mocking interfaces is a nice way to write unit tests where you can easily control the behaviour of the mocked object.

Moq creates a struct that has a function field for each method, which you can declare in your test code.

In this example, Moq generated the EmailSenderMock type:

func TestCompleteSignup(t *testing.T) {

	var sentTo string

	mockedEmailSender = &EmailSenderMock{
		SendFunc: func(to, subject, body string) error {
			sentTo = to
			return nil
		},
	}

	CompleteSignUp("[email protected]", mockedEmailSender)

	callsToSend := len(mockedEmailSender.SendCalls())
	if callsToSend != 1 {
		t.Errorf("Send was called %d times", callsToSend)
	}
	if sentTo != "[email protected]" {
		t.Errorf("unexpected recipient: %s", sentTo)
	}

}

func CompleteSignUp(to string, sender EmailSender) {
	// TODO: this
}

The mocked structure implements the interface, where each method calls the associated function field.

Tips

  • Keep mocked logic inside the test that is using it
  • Only mock the fields you need
  • It will panic if a nil function gets called
  • Name arguments in the interface for a better experience
  • Use closured variables inside your test function to capture details about the calls to the methods
  • Use .MethodCalls() to track the calls
  • Use .ResetCalls() to reset calls within an invidual mock's context
  • Use go:generate to invoke the moq command
  • If Moq fails with a go/format error, it indicates the generated code was not valid. You can run the same command with -fmt noop to print the generated source code without attempting to format it. This can aid in debugging the root cause.

License

The Moq project (and all code) is licensed under the MIT License.

Moq was created by Mat Ryer and David Hernandez, with ideas lovingly stolen from Ernesto Jimenez. Featuring a major refactor by @sudo-suhas, as well as lots of other contributors.

The Moq logo was created by Chris Ryer and is licensed under the Creative Commons Attribution 3.0 License.

moq's People

Contributors

breml avatar cbaker avatar cgorenflo avatar dahernan avatar dedalusj avatar djui avatar dpetersen avatar fvosberg avatar gabrielbussolo avatar haraldnordgren avatar haunt98 avatar ivansafonov avatar kl09 avatar maneac avatar matryer avatar meamidos avatar metalrex100 avatar pdrum avatar piotrrojek avatar romanlevin avatar samherrmann avatar soniah avatar steveoc64 avatar sudo-suhas avatar timvosch avatar tprebs avatar uji avatar umputun avatar veloek avatar warmans avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

moq's Issues

Generation of variadic arguments not works like expected

When you mock grpc client services it will generate a different interface.

Following interface:

type Service Interface{
    Call(ctx context.Context, in CallRequest, opts ...grpc.CallOption) (*CallResponse, error)
}

generates

type ServiceMock struct {
    CallFunc func(ctx context.Context, in *CallRequest, opts []grpc.CallOption) (*CallResponse, error)
}

func (mock *ServiceMock) Call(ctx context.Context, in *CallRequest, opts []grpc.CallOption) (*CallResponse, error) {
    if mock.CallFunc == nil {
        panic("moq: CallFunc is nil but was just called")
    }
    return mock.CallFunc(ctx, in, opts)
}

but I would expect

type ServiceMock struct {
    CallFunc func(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error)
}

func (mock *ServiceMock) Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error) {
    if mock.CallFunc == nil {
        panic("moq: CallFunc is nil but was just called")
    }
    return mock.CallFunc(ctx, in, opts...)
}

Functions without returns handled incorrectly

Hi, I generated a mock of an interface like this:

type MyInterface interface {
    MyFunc()
}

It generates the following code:

// MyFunc calls MyFuncFunc.
func (mock *MyInterfaceMock) MyFunc() {
    if mock.MyFuncFunc == nil {
        panic("moq: MyInterfaceMock.MyFuncFunc is nil but was just called")
    }
    return mock.MyFuncFunc()
}

This is invalid, of course, as MyFunc() does not have a return value.

How does one mock a third-party package?

The examples in the readme all show how to generate a mock for an interface you own.

Is it possible to generate a moq for a standard library interface? Or for another interface on your gopath?

Nothing I try seems to work:

  • moq . io.Reader
  • moq . io/Reader
  • moq -pkg io . Reader

Ignored method parameters cause errors on generation

When a parameter is _ *FooStruct then the generation of the mock creates invalid callInfo struct.

Take the example of some gRPC service parameters that could look like:

Foo(ctx context.Context, _ *types.Empty)

This will generate a callInfo that looks like:

	callInfo := struct {
		Ctx context.Context
		_   *types.Empty
	}{
		Ctx: ctx,
		_:   _,
	}

It also will then try to call the mock.FooFunc(ctx, _) which is also invalid.

What the desired result is to have any _ parameters ignore in the callInfo initialization stage (_: _, is invalid) and to replace the _ in the FooFunc call with a nil.

If this is to support it for other types too, it may get more complex when trying to assign it to the default value of the incoming type.

Typo in README

Hello, I noticed a small problem on the README file on line 61:

This this example, Moq generated the `EmailSenderMock` type:

Package with the same name as source package is not imported

Source:

package mypackage

import anotherpkg "github.com/noodlensk/moq/issues/repo1/mypackage"

//go:generate moq -out client_moq.go . Client
type Client interface {
	GetSomeThing() anotherpkg.MyStruct
}

Result mock:

package mypackage

import (
	"sync"
)
...
type ClientMock struct {
	// GetSomeThingFunc mocks the GetSomeThing method.
	GetSomeThingFunc func() MyStruct
...
}

Expected mock:

package mypackage

import (
	"sync"
        anotherpkg "github.com/noodlensk/moq/issues/repo1/mypackage"
)
...
type ClientMock struct {
	// GetSomeThingFunc mocks the GetSomeThing method.
	GetSomeThingFunc func() anotherpkg.MyStruct
...
}

I've checked moq source code, I guess it should be fixed by:

  • Support packages aliases in import section
  • Compare packages paths instead of packages names

-fmt command to specify formats `gofmt` or `goimports`

More a request for improvement than a bug report.

Request:

After generating the moq files, run them through gofmt.

Use case:

When manually changing a generated file, saving it causes gofmt to run, leading to a bigger diff in version control. I know that I could a) simply avoid changing the file manually and instead re-generate it or b) perform the changes in an editor that does not automatically run gofmt, or c) add a pre-commit hook to run gofmt on all .go files.
It would be nice to have nonetheless and solve a minor pain point for me :)

Generated output files have executable (0755) file mask

I assume this is not intentional and they should have 0644:

$ moq -out t_mock_test.go vendor/github.com/stretchr/testify/require TestingT

$ ls -lh t_mock_test.go
-rwxr-xr-x 1 uwe staff 2.9K Dec 23 23:23 t_mock_test.go

The subject line:

moq/main.go

Line 57 in c80e9a7

err = ioutil.WriteFile(*outFile, buf.Bytes(), 0777)

Putting all mocks together into one single package

Hi everyone!

Why moq is not allowed to generate mocks in an arbitrary directory? Only current directory or subdirectory.

First of all I want to say that I'm new in golang and don't have enough experience.
Let's imagine I have some project with couple of modules. Every module have core package with data types and interfaces. Other than that each module can have concrete implementations of this interfaces. Core packages of modules can import other core packages but not concrete implementations.

So now I want to make one single packge that contains mocks for all the interfaces in my project. It looks simple and clear and seems like it should work. There's no any cyclic dependencies.

module1
  interfaces.go
  concrete1
    implementation.go
    implementation_test.go
  concrete2
    implementation.go
    implementation_test.go

module2
  interfaces.go
  concrete1
    implementation.go
    implementation_test.go
  concrete2
    implementation.go
    implementation_test.go

mocks
  module1.go
  module2.go

I don't like to put mocks in the same package, 'cause it always compiles with the main code and it breaks test coverage percentage. Nested mocks directory causes messy imports in the tests.

BTW, I've made a fork https://github.com/IvanSafonov/moq where it's possible to generate mocks in any directory.

Mocks cannot be generated from *_test.go files

I would like to mock an external interface provided by the AWS SDK. To do so, I create a local type alias:

// dynamo.go
package dynamo

import "github.com/aws/aws-sdk-go-v2/service/dynamodb/dynamodbiface"

//go:generate moq -out ../mocks/dynamodb.go -pkg mocks . DynamoDBAPI

type DynamoDBAPI = dynamodbiface.DynamoDBAPI

However, this increases the API surface of my dynamo package by adding another public interface to it which can and should not be used except for mocking. To mitigate that, I would like to move the code above into the respective testing package dynamo_test. However, when I do so, moq complains about the interface not being found:

// dynamo_test.go
package dynamo_test

import "github.com/aws/aws-sdk-go-v2/service/dynamodb/dynamodbiface"

//go:generate moq -out ../mocks/dynamodb.go -pkg mocks . DynamoDBAPI

type DynamoDBAPI = dynamodbiface.DynamoDBAPI
$ go generate ./...

cannot find interface DynamoDBAPI
moq [flags] destination interface [interface2 [interface3 [...]]]
  -out string
        output file (default stdout)
  -pkg string
        package name (default will infer)
dynamo_test.go:5: running "moq": exit status 1

Custom importer may be causing errors

I see in #18 that @johanbrandhorst mentioned he was getting errors that look like the one below when importing with a vendor folder.

file.go:36:37: cannot use bla.Bla (of type github.com/group/bla.Bla) as <myrepo>/vendor/github.com/group/bla.Bla value in argument to something.Something

I also encountered this issue the other day, and wanting to find a solution so I could still use moq, I spent a few minutes playing with the code. The result was the following minimal patch, which stopped the errors I was seeing and allowed moq to generate the mocks I was after.

diff --git a/pkg/moq/moq.go b/pkg/moq/moq.go
index f4b43c0..d9a75b2 100644
--- a/pkg/moq/moq.go
+++ b/pkg/moq/moq.go
@@ -6,6 +6,7 @@ import (
        "fmt"
        "go/ast"
        "go/format"
+       "go/importer"
        "go/parser"
        "go/token"
        "go/types"
@@ -79,7 +80,7 @@ func (m *Mocker) Mock(w io.Writer, name ...string) error {
                        files[i] = file
                        i++
                }
-               conf := types.Config{Importer: newImporter(m.src)}
+               conf := types.Config{Importer: importer.Default()}
                tpkg, err := conf.Check(m.src, m.fset, files, nil)
                if err != nil {
                        return err

I don't have a very deep understanding of this issue, but it seems the custom importer moq is currently using may be outdated. The importer in the stdlib seems to work without the errors mentioned above.

fix type names

Type names seem to be a path, rather than the type name:

CreateFunc: func(ctx context.Context, person *../../example.Person, confirm bool) error {

Should be:

CreateFunc: func(ctx context.Context, person *Person, confirm bool) error {

or if in a different package:

CreateFunc: func(ctx context.Context, person *example.Person, confirm bool) error {

Generated files contain "TODO" strings which are searched by some editors/plugins and clutter search results

Some IDEs, such as Goland, and plugins, such as Visual Studio Code's TODO Highlight, search your code for "TODO" in comments so they can display a list of outstanding TODO comments. It's not uncommon to search for "TODO" regardless of your dev environment. Files generated by moq contain comments with TODO and are displayed in these IDEs/plugins and clutter search results.

Could moq either modify those comments to not include "TODO" or have a flag added to suppress them?

moq having issues with build tags

trying to use moq to mock an interface from a package that imports "github.com/garyburd/redigo/redis" elsewhere in the code...I'm getting:

# go generate
main.go:11:2: could not import github.com/garyburd/redigo/redis (/go/src/github.com/graymeta/mf2/vendor/github.com/garyburd/redigo/redis/pre_go17.go:8:6: cloneTLSClientConfig redeclared in this block)
moq [flags] destination interface [interface2 [interface3 [...]]]
  -out string
        output file (default stdout)
  -pkg string
        package name (default will infer)
log.go:3: running "moq": exit status 1

You can reproduce it with this:

package main

//go:generate moq -out mock_logger.go . Logger

import (
    "log"

    "github.com/garyburd/redigo/redis"
)

func main() {
    p := redis.Pool{
        Dial: func() (redis.Conn, error) {
            return redis.Dial("tcp", "127.0.0.1:6379")
        },
    }
    log.Printf("%v", p)
}

type Logger interface {
    SomeFunc(a int)
}

It looks like that redis package is using build tags for different versions of go: https://github.com/garyburd/redigo/blob/master/redis/go17.go#L1

fix package name

see github.com/matryer/drop for how to obtain destination package name

moq errors with "cannot find package" looking for a path instead of a package name

We have used moq for a few months now, but recently updated a few interfaces and needed to regenerate the mock objects. I ran the same command as before:
moq -out ../testutils/test_interface.go . MessageSender

This command was run from a subdirectory of our project, within the GOPATH folder. However, instead of generating the files as expected, it yields an error:
cannot find package "C:\\Users\\username\\src\\{our_project_name}\\{folder_I_ran_from}
followed by "no initial packages were loaded"

I actually copy/pasted the command from the last time I ran it, and am certain that I'm running it from the same directory. Has something changed w.r.t to Golang version requirements or the parameters that must be supplied? It looks like this command should run based on the current documentation.

I'm running Go 1.8.3 and a coworker is running 1.9, and we're both seeing the same issue.

go:generate seems to ignore -pkg flag

First off, thanks for the cool tool, it's a time saver.
I have noticed that when generating mocks via go generate <pkg> and the file to be mocked having
//go:generate moq -out ./mock/service_moq.go -pkg mock . Service

The generated file has the original package name of service and not mock as expected. When running moq -out ./mock/service_moq.go -pkg mock . Service from the service directory the generated file package is set to mock as expected.

Let me know if you need any further info from me.

Moq ignores build constraints for vendored code

It appears that for vendored dependencies, moq ignores build tags / constraints. Here is an example which reproduces the issue on my machine (running go version go1.8.3 darwin/amd64):

#!/bin/bash

# Set up

function run_moq() (
    cd $PACKAGE_PATH
    moq pak MyInterface
    echo
)

export GOPATH=$PWD/go-example
PROJECT_PATH=$GOPATH/src/github.com/username/project
PACKAGE_PATH=$PROJECT_PATH/internal
mkdir -p $PACKAGE_PATH/pak

echo \
'package pak

import _ "golang.org/x/net/context"

type MyInterface interface {}
' > $PACKAGE_PATH/pak/file.go


# Attempt 1: Gives 'could not import golang.org/x/net/context' as expected.
run_moq

# Attempt 2: At this point it works.
go get golang.org/x/net/context
run_moq

# Attempt 3: Simulate vendoring, in reality I would use 'dep ensure', but this
# achieves the same result with fewer files. Now it fails!
mkdir -p $PROJECT_PATH/vendor/golang.org/x/net
cp -r $GOPATH/src/golang.org/x/net/context $PROJECT_PATH/vendor/golang.org/x/net
run_moq

The last execution of run_moq gives this error message:

pak/file.go:3:10: could not import golang.org/x/net/context (.../src/github.com/username/project/vendor/golang.org/x/net/context/pre_go17.go:47:2: background redeclared in this block)

Manually removing some of thepre_* files inside the net/context library removes the error.

It appears that despite the build constraints, multiple exclusive files are run by Go and objects are redeclared.

Run example.go for to long

I've been through two examples. one of them are going well, which is described in the blog. But another has met some error.
I've downloaded the example.go in github and used command go get github.com/matryer/moq && go generate as the preview example. However it seemed like not going to finish. Perhaps a dead loop?

and my screen shot as follow:

moq_error

Source instead of destination

Shouldn't it be source instead of destination in moq [flags] destination interface [interface2 [interface3 [...]]]? Also, in main.go, moq.New(destination, *pkgName) gets called, however, New has parameter src, not destination - func New(src, packageName string) (*Mocker, error).

Vendor dir breaks moq (sometimes)

This has been driving me crazy for about a day. Essentially it would appear that the presence of a vendor directory causes some kind of a problem related to checking the validity of packages. Here is some code to illustrate.

package foo

import _ "github.com/lib/pq"

type Foo interface {
}

generate the mock moq . Foo

// Code generated by moq; DO NOT EDIT
// github.com/matryer/moq

package foo
<...snip...>

OK all is good. Now run dep ensure and re-run the mock moq . Foo:

foo.go:3:10: could not import github.com/lib/pq (/home/.../moq-test/vendor/github.com/lib/pq/buf.go:7:2: could not import github.com/lib/pq/oid (/home/.../moq-test/vendor/github.com/lib/pq/oid/gen.go:5:1: package main; expected oid))

That's weird. The pq project does indeed have a mix of packages in that directory but moq only cares about this if the package is vendored.

I've tried digging into the code but it's not at all clear what's causing this. Just disabling some vendor related code doesn't seem to help.

The error is returned here:

conf := types.Config{Importer: newImporter(m.src)}
tpkg, err := conf.Check(m.src, m.fset, files, nil)
if err != nil {
	return err
}

Extra information:
moq version: latest master
go version go1.9.2
os: ubuntu

Extra Mystery:
A colleague on osx can still generate mocks on a larger project which fails for me on linux, but CAN re-produce the error with the example above.

Invalid import path for destination package

It looks like moq generating non compilable code in case it has to add an import to the destination package.
Here's some code to reproduce:
https://github.com/ncsibra/moqtest
Run go test ./... from the root, which gives an it/storage_mock_test.go:7:2: local import "../storage" in non-local package error.

I want to write some integration test in a separate package and I want to generate the mocks with moq.
The package to mock contains multiple interfaces and one of the interface refers to an other in the same package, which cause the problem.
Based on the documentation we need to add a path as a destination, so in my case, I added ../storage.
It generates the mock file without any problem, but does not resolve the correct package path, just simply adds the destination argument as an import path.
If I use an absolute path as destination the same happens.

I assume it's a bug and it should resolve to the correct import path.

Bad error when no GOPATH is set

E.g moq . containerOnlineChecker gives

import "/home/ammar/go/src/go.coder.com/hconproxy/internal/hconproxyd": cannot import absolute path
no initial packages were loaded
moq [flags] destination interface [interface2 [interface3 [...]]]
  -out string
    	output file (default stdout)
  -pkg string
    	package name (default will infer)
Error walking: no initial packages were loaded

Edit:

Turns out my GOPATH wasn't set. I was relying on the default ~/go GOPATH. A better error should be provided.

moq causes import cycle since #62

Since updating moq a few hours ago we are getting import cycles when re-generating the mocks. I strongly suspect this is due to #62. The line marked with a comment "NEW and causes problems" was not inserted by moq until now.

File: api/usecase/moqproblem/usecase.go

package moqproblem

type File struct {
	Archive string
	Host    string
	Path    string
}

//go:generate moq -pkg moqproblem -out corrupted_file_getter_moq.go . CorruptedFileGetter

type CorruptedFileGetter interface {
	GetCorruptedFiles(archive string) ([]File, error)
}

File: api/usecase/moqproblem/corrupted_file_getter_moq.go

// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq

package moqproblem

import (
	"private.com/repo.git/api/usecase/moqproblem" // <---------- NEW and causes problems
	"sync"
)

var (
	lockCorruptedFileGetterMockGetCorruptedFiles sync.RWMutex
)

// ...

EDIT: Update the example to be executable. Try it out:

mkdir -p ~/go/src/private.com/repo.git/api/usecase/moqproblem
# Place the first file above in ~/go/src/private.com/repo.git/api/usecase/moqproblem/usecase.go
cd ~/go/src/private.com/repo.git/
go generate ./...
go test ./...

You will get the following error:

can't load package: import cycle not allowed
package private.com/repo.git/api/usecase/moqproblem
	imports private.com/repo.git/api/usecase/moqproblem
import cycle not allowed
package private.com/repo.git/api/usecase/moqproblem
	imports private.com/repo.git/api/usecase/moqproblem

Generate mock for interface from external package outside of GOPATH

We have a project, which uses Go modules (introduced with Go 1.11) and therefore, this project resides outside the GOPATH and is compiled with GO111MODULE=on.

In order to generate a mock for an interface, which is defined externally (3rd party package), we use the following command:

moq -out snsapi_mocks_test.go -pkg mypkg $(go list -f '{{.Dir}}' github.com/aws/aws-sdk-go-v2/service/sns/snsiface) SNSAPI

Prior to Go 1.11 and the usage of Go modules the go list command above returned the location of the package within the GOPATH (/home/user/go/src/github.com/aws/aws-sdk-go-v2/service/sns/snsiface), which was then properly handled by moq.

Now with Go 1.11 and Go modules enabled, the go list command returns the location of the source code in the new location $HOME/go/pkg/mod/... (e.g. /home/user/go/pkg/mod/github.com/aws/[email protected]+incompatible/service/sns/snsiface).

If this location is then given to mod, the following error is returned:

import "/home/user/go/pkg/mod/github.com/aws/[email protected]+incompatible/service/sns/snsiface": cannot import absolute path

Missing imports after #59

@matryer Thanks for merging my PRs. Unfortunately in #59 I introduced a bug. The necessary import statements for the static import check is missing. I will try to have a look tonight how to fix this.

Moq hangs

Example 1: GOROOT

$ moq $(go env GOROOT)/src/database/sql/driver Driver
^\SIGQUIT: quit
PC=0x105415b m=0 sigcode=0

goroutine 0 [idle]:
runtime.mach_semaphore_wait(0xa03, 0x0, 0xc42022c800, 0x7ffeefbff3a0, 0x101efb8, 0x1409be0, 0x7ffeefbff3b8, 0x104e9a3, 0xffffffffffffffff, 0x101c0b1, ...)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/sys_darwin_amd64.s:542 +0xb
runtime.semasleep1(0xffffffffffffffff, 0x101c0b1)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/os_darwin.go:417 +0x52
runtime.semasleep.func1()
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/os_darwin.go:436 +0x33
runtime.semasleep(0xffffffffffffffff, 0xc420031270)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/os_darwin.go:435 +0x44
runtime.notesleep(0x140a228)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/lock_sema.go:167 +0xe9
runtime.stopm()
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:1947 +0xe5
runtime.findrunnable(0xc42002d900, 0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:2404 +0x4fa
runtime.schedule()
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:2530 +0x13b
runtime.park_m(0xc420001980)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:2593 +0xb6
runtime.mcall(0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/asm_amd64.s:351 +0x5b

goroutine 1 [runnable]:
syscall.Syscall(0x152, 0xc420196030, 0xc420198038, 0x0, 0xffffffffffffffff, 0x0, 0x2)
	/usr/local/Cellar/go/1.10beta1/libexec/src/syscall/asm_darwin_amd64.s:16 +0x5
syscall.Stat(0xc420196020, 0xb, 0xc420198038, 0xb, 0xc420196020)
	/usr/local/Cellar/go/1.10beta1/libexec/src/syscall/zsyscall_darwin_amd64.go:1192 +0x97
os.Stat(0xc420196020, 0xb, 0xc420196020, 0xb, 0x0, 0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/os/stat_unix.go:32 +0x5c
github.com/matryer/moq/pkg/moq.vendorPath(0x7ffeefbff7f4, 0x1, 0xc42001a3d7, 0x3, 0xc42012b110, 0x12aa2a3, 0xe)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:79 +0x17b
github.com/matryer/moq/pkg/moq.gopathDir(0x7ffeefbff7f4, 0x3e, 0xc42001a3d7, 0x3, 0xc42012b1d8, 0x104b663, 0x125e8e0, 0x3aac0)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:49 +0x82
github.com/matryer/moq/pkg/moq.(*customImporter).fsPkg(0xc420133e30, 0xc42001a3d7, 0x3, 0x3, 0x1427640, 0x10d2d00)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:107 +0x73
github.com/matryer/moq/pkg/moq.(*customImporter).Import(0xc420133e30, 0xc42001a3d7, 0x3, 0x0, 0x0, 0xc42012b300)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:39 +0xe4
go/types.(*Checker).importPackage(0xc420160000, 0xbb, 0xc42001a3d7, 0x3, 0xc420016320, 0x3e, 0x9)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/resolver.go:162 +0x63e
go/types.(*Checker).collectObjects(0xc420160000)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/resolver.go:256 +0x10de
go/types.(*Checker).checkFiles(0xc420160000, 0xc42012e630, 0x2, 0x2, 0x0, 0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/check.go:237 +0x97
go/types.(*Checker).Files(0xc420160000, 0xc42012e630, 0x2, 0x2, 0xc420136b40, 0x1218eb7)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/check.go:230 +0x49
go/types.(*Config).Check(0xc42013e4c0, 0x7ffeefbff7f4, 0x3e, 0xc420020380, 0xc42012e630, 0x2, 0x2, 0x0, 0x110a23f, 0xc42012bbb8, ...)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/api.go:351 +0x12f
github.com/matryer/moq/pkg/moq.(*Mocker).Mock(0xc42013e480, 0x12db200, 0xc42000c018, 0xc42000e1d0, 0x1, 0x1, 0x0, 0x1006dfd)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/moq.go:126 +0x264
main.main()
	/Users/uwe/dev/go/src/github.com/matryer/moq/main.go:51 +0x2b0

rax    0xe
rbx    0x140a0e0
rcx    0x7ffeefbff358
rdx    0x7ffeefbff3d8
rdi    0xa03
rsi    0x1
rbp    0x7ffeefbff390
rsp    0x7ffeefbff358
r8     0x0
r9     0xa
r10    0x3bb89a3a
r11    0x286
r12    0xcb2f76cfe19a
r13    0x0
r14    0x1051940
r15    0x0
rip    0x105415b
rflags 0x286
cs     0x7
fs     0x0
gs     0x0

Example 2: Symlinks

Many Go tools have a problem with running them from a symlinked directory (and also e.g. dep). These sometimes tell the user what's wrong. moq also has a problem with this condition but then instead just busy loops:

$ pwd
/Users/uwe/dev/company/pkg

$ moq -out t_mock_test.go vendor/github.com/stretchr/testify/require TestingT
# Hanging (dump forced with `Ctrl-\`)
^\SIGQUIT: quit
PC=0x105415b m=0 sigcode=0

goroutine 0 [idle]:
runtime.mach_semaphore_wait(0x1303, 0x0, 0xc420373000, 0x7ffeefbff3a0, 0x101efb8, 0x1409be0, 0x7ffeefbff3b8, 0x104e9a3, 0xffffffffffffffff, 0x101c0b1, ...)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/sys_darwin_amd64.s:542 +0xb
runtime.semasleep1(0xffffffffffffffff, 0x101c0b1)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/os_darwin.go:417 +0x52
runtime.semasleep.func1()
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/os_darwin.go:436 +0x33
runtime.semasleep(0xffffffffffffffff, 0xc42002a170)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/os_darwin.go:435 +0x44
runtime.notesleep(0x140a228)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/lock_sema.go:167 +0xe9
runtime.stopm()
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:1947 +0xe5
runtime.findrunnable(0xc42002b400, 0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:2404 +0x4fa
runtime.schedule()
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:2530 +0x13b
runtime.park_m(0xc420188a80)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/proc.go:2593 +0xb6
runtime.mcall(0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/runtime/asm_amd64.s:351 +0x5b

goroutine 1 [runnable]:
path.(*lazybuf).string(...)
	/usr/local/Cellar/go/1.10beta1/libexec/src/path/path.go:52
path.Clean(0xc42058dce0, 0x11, 0x3, 0x12a7bb5)
	/usr/local/Cellar/go/1.10beta1/libexec/src/path/path.go:139 +0x761
path.Join(0xc4201426a0, 0x3, 0x3, 0x1, 0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/path/path.go:158 +0xa4
github.com/matryer/moq/pkg/moq.vendorPath(0xc4201ecf50, 0x1, 0xc4201600a1, 0x8, 0xc4201427a0, 0x100fa29, 0xc42021d840)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:75 +0x141
github.com/matryer/moq/pkg/moq.gopathDir(0x7ffeefbff820, 0x2a, 0xc4201600a1, 0x8, 0xc420170448, 0xc420142850, 0x10d56e1, 0xc420170420)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:49 +0x82
github.com/matryer/moq/pkg/moq.(*customImporter).fsPkg(0xc4201546f0, 0xc4201600a1, 0x8, 0x8, 0x1427640, 0x10d2d00)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:107 +0x73
github.com/matryer/moq/pkg/moq.(*customImporter).Import(0xc4201546f0, 0xc4201600a1, 0x8, 0x0, 0x0, 0xc420142a00)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:39 +0xe4
go/types.(*Checker).importPackage(0xc42016e0e0, 0x98, 0xc4201600a1, 0x8, 0xc420178780, 0x43, 0x9)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/resolver.go:162 +0x63e
go/types.(*Checker).collectObjects(0xc42016e0e0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/resolver.go:256 +0x10de
go/types.(*Checker).checkFiles(0xc42016e0e0, 0xc420201fc0, 0x6, 0x8, 0x0, 0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/check.go:237 +0x97
go/types.(*Checker).Files(0xc42016e0e0, 0xc420201fc0, 0x6, 0x8, 0xc420213540, 0xc420143180)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/check.go:230 +0x49
go/types.(*Config).Check(0xc42021d900, 0xc4200182d1, 0x22, 0xc42015c200, 0xc420201fc0, 0x6, 0x8, 0x0, 0x0, 0xc420143288, ...)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/api.go:351 +0x12f
github.com/matryer/moq/pkg/moq.(*customImporter).fsPkg(0xc4201546f0, 0xc4200182d1, 0x22, 0x22, 0x1427640, 0x10d2d00)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:144 +0x5cd
github.com/matryer/moq/pkg/moq.(*customImporter).Import(0xc4201546f0, 0xc4200182d1, 0x22, 0x0, 0x0, 0xc420143300)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/importer.go:39 +0xe4
go/types.(*Checker).importPackage(0xc42016e000, 0x66e, 0xc4200182d1, 0x22, 0xc420014880, 0x2a, 0x9)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/resolver.go:162 +0x63e
go/types.(*Checker).collectObjects(0xc42016e000)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/resolver.go:256 +0x10de
go/types.(*Checker).checkFiles(0xc42016e000, 0xc420154660, 0x5, 0x5, 0x0, 0x0)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/check.go:237 +0x97
go/types.(*Checker).Files(0xc42016e000, 0xc420154660, 0x5, 0x5, 0xc4201522d0, 0x1218eb7)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/check.go:230 +0x49
go/types.(*Config).Check(0xc42015c180, 0x7ffeefbff820, 0x2a, 0xc420020380, 0xc420154660, 0x5, 0x5, 0x0, 0x110a23f, 0xc420143bb8, ...)
	/usr/local/Cellar/go/1.10beta1/libexec/src/go/types/api.go:351 +0x12f
github.com/matryer/moq/pkg/moq.(*Mocker).Mock(0xc42015c140, 0x12daf60, 0xc4200c4230, 0xc42000e180, 0x1, 0x1, 0x0, 0x1006dfd)
	/Users/uwe/dev/go/src/github.com/matryer/moq/pkg/moq/moq.go:126 +0x264
main.main()
	/Users/uwe/dev/go/src/github.com/matryer/moq/main.go:51 +0x2b0

rax    0xe
rbx    0x140a0e0
rcx    0x7ffeefbff358
rdx    0x7ffeefbff3d8
rdi    0x1303
rsi    0x1
rbp    0x7ffeefbff390
rsp    0x7ffeefbff358
r8     0x0
r9     0x1409fa8
r10    0xa
r11    0x286
r12    0xb1c5323bbc08
r13    0x3
r14    0x2
r15    0x100
rip    0x105415b
rflags 0x286
cs     0x7
fs     0x0
gs     0x0

Same from actual directory:

$ pwd
/Users/uwe/dev/company/pkg

$ cd -P .

$ pwd
/Users/uwe/dev/go/src/github.com/company/pkg

$ moq -out t_mock_test.go vendor/github.com/stretchr/testify/require TestingT

$

Optionally generating mock tests

Hello!

We're using moq successfully for our internal company services and loving it.

Our continuous integrations system forces a strict test coverage threshold, this has lead to us repeatedly writing small tests for the generated mocks, a process that could be automated.

Is this something that could be considered for the moq package itself? An optional flag that would generate _test files for the mocks. We're happy to contribute towards this goal.

Thank you

Import aliases not maintained, cannot import multiple packages with same name

We have an unfortunate case where we have packages with the same name imported:

package things

import (
	"context"

	pclient "github.com/example/client"
	mclient "github.com/micro/go-micro/client"
)

//go:generate moq -out client.mock.go . Client

type Client interface {
	GetByID(ctx context.Context, in *pclient.Client, opts ...mclient.CallOption) (*pclient.Response, error)
}

The generated code doesn't retain the import aliases meaning we have to find/replace a bunch of code post-generate. Any chance moq can retain the import aliases?

Thanks in advance!

Write the mock in the corresponding _test package

Hi Mat,

at first, thank you very much for this great package. Unfortunately I'm a little bit struggling with getting started, so I would like to help improve the documentation with my misunderstanding ;).

I've created a little example: https://github.com/fvosberg/moqtest

When I try

//go:generate moq -out service_moq_test.go -pkg moqtest_test github.com/fvosberg/moqtest Service

Then I get

open github.com/fvosberg/moqtest: no such file or directory

And when I use

//go:generate moq -out service_moq_test.go -pkg moqtest_test . Service

I get on go test

service_moq_test.go:8:2: local import "." in non-local package

Am I using the package wrong, or is this case not implemented? I would really appreciate some help and when it is not implemented right now, I would really love help implementing it.

Cheers
Fredi

Followed instructions in blog but moq seems to be doing something else

I tried to generate a mock object from this file:
------------------------cache.go-----------------------
package impls

//go:generate moq -out cache_mock_test.go . Cache

//Cache --
type Cache interface {
//basic ops
Store(key, value string) error
StoreWithTTL(key, value string, ttl int64) error
}`

Tried running go generate:

% go generate

errors.go:15:40: cannot use codes.AlreadyExists (constant 6 of type google.golang.org/grpc/codes.Code) as google.golang.org/grpc/codes.Code value in argument to grpc.Errorf
moq [flags] destination interface [interface2 [interface3 [...]]]
-out string
output file (default stdout)
-pkg string
package name (default will infer)
cache.go:3: running "moq": exit status 1

I also tried running moq on the command line, still got the error above. Is this really working?

License

Definitely not an issue, more of a question:

We use a copyright linter for our company projects which currently (without modification) requires a copyright header on all Go files. Before adjusting the linter I would like to ask in general if you happen to know if it is legally permitted to prefix auto-generated files from a MIT licensed project like moq?

Moq breaks when a dependency uses build tags to exclude duplicate code

When running moq in a package that imports code using build tags, moq fails to compile if any imports include duplicate method declarations that would otherwise be resolved by build tags.
For example github.com/gorilla/mux/context_native.go and github.com/gorilla/mux/context_gorilla.go both declare a contextGet method - one or other file should be excluded according to a build tag:

// +build !go1.7

Attempting to generate mocks against this file:

package moqtest

import "github.com/gorilla/mux"

//go:generate moq -out mock_test.go . MyInterface

type MyInterface interface {
	DoStuff() string
}

func foo() {

	router := mux.NewRouter()

	println(router)
}

results in the following error:

live.go:3:8: could not import github.com/gorilla/mux (/.../vendor/github.com/gorilla/mux/context_native.go:10:6: contextGet redeclared in this block)
moq [flags] destination interface [interface2 [interface3 [...]]]
  -out string
    	output file (default stdout)
  -pkg string
    	package name (default will infer)

go/format error

When executing moq with (roughly) the following command line, I get a go/format error:

$ moq -out mocks_test.go -pkg my/package/repo/path . Repository
go/format: 4:15: expected ';', found '.'

I am not sure from which file this error comes from, but at line 4 of the file where the Repository interface is declared, there is neither a ; nor ..

Use function or mock name for panic prefix

I think using the function or mock type name as panic prefix is more Go idiomatic, even though I might understand there is some "branding value". For a reader of the panic that was not involved in the mock generator phase (larger teams) it can be confusing to recover where or what moq in this context is.

I would like to suggest changing the following (the "branding value" is still given in the auto-generated header):

panic("moq: {{$obj.InterfaceName}}Mock.{{.Name}}Func is nil but {{$obj.InterfaceName}}.{{.Name}} was just called")

-panic("moq: {{$obj.InterfaceName}}Mock.{{.Name}}Func is nil but {{$obj.InterfaceName}}.{{.Name}} was just called") 
+panic("{{$obj.InterfaceName}}Mock: {{.Name}}Func is nil but {{.Name}} was just called")

Allow specifying name for generated mock

Right now, the name for the generated mock is {{.InterfaceName}}Mock and it works well for most cases. However, I wanted to keep all the generated mocks in a separate mock pkg as suggested by Ben Johnson - https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1#f68c. The problem was that I had multiple interfaces with the same name in different packages(a.APIClient, b.APIClient, c.APIClient ...). So what I wanted was to have the mocks of the form mock.AClient, mock.BClient etc. I forked the repo and made minimal changes to make this possible - sudo-suhas/moqit. Do you think this is a feature worth having?

Infinite loop

If there is a recursive import in the code and the interface to be mocked is in one of the packages in the chain of recursive imports, moq will go into an infinite loop rather than generating an error.

Function that do not return values should not be mandatory

I'm interested in making mocks more lenient (in the style of Mockito). That is, when a function does not return any value, then it should probably not be mandatory.
In other words, the mock should not panic when called on a function that is nil, as long as it does not return any value.

Thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.