Add static interface implementation check

Add an additional line of code per interface to the generated mock file,
which allows the go compiler to statically check if the mock implements
the mocked interface.
This commit is contained in:
Lucas Bremgartner 2018-06-04 14:22:28 +02:00 committed by Lucas Bremgartner
parent c4521bcc9d
commit b21592468b
9 changed files with 93 additions and 4 deletions

View File

@ -13,6 +13,10 @@ var (
lockPersonStoreMockGet sync.RWMutex
)
// Ensure, that PersonStoreMock does implement PersonStore.
// If this is not the case, regenerate this file with moq.
var _ PersonStore = &PersonStoreMock{}
// PersonStoreMock is a mock implementation of PersonStore.
//
// func TestSomethingThatUsesPersonStore(t *testing.T) {

View File

@ -13,6 +13,10 @@ var (
lockMyInterfaceMockTwo sync.RWMutex
)
// Ensure, that MyInterfaceMock does implement MyInterface.
// If this is not the case, regenerate this file with moq.
var _ MyInterface = &MyInterfaceMock{}
// MyInterfaceMock is a mock implementation of MyInterface.
//
// func TestSomethingThatUsesMyInterface(t *testing.T) {

View File

@ -2,12 +2,12 @@ package main
import (
"bytes"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"errors"
"github.com/matryer/moq/pkg/moq"
)

View File

@ -171,6 +171,10 @@ func (m *Mocker) Mock(w io.Writer, name ...string) error {
doc.Imports = append(doc.Imports, stripVendorPath(pkgToImport))
}
if tpkg.Name() != m.pkgName {
doc.SourcePackagePrefix = tpkg.Name() + "."
}
var buf bytes.Buffer
err = m.tmpl.Execute(&buf, doc)
if err != nil {
@ -250,6 +254,7 @@ func pkgInfoFromPath(src string) (*loader.PackageInfo, error) {
type doc struct {
PackageName string
SourcePackagePrefix string
Objects []obj
Imports []string
}

View File

@ -42,6 +42,40 @@ func TestMoq(t *testing.T) {
}
}
func TestMoqWithStaticCheck(t *testing.T) {
m, err := New("testpackages/example", "")
if err != nil {
t.Fatalf("moq.New: %s", err)
}
var buf bytes.Buffer
err = m.Mock(&buf, "PersonStore")
if err != nil {
t.Errorf("m.Mock: %s", err)
}
s := buf.String()
// assertions of things that should be mentioned
var strs = []string{
"package example",
"var _ PersonStore = &PersonStoreMock{}",
"type PersonStoreMock struct",
"CreateFunc func(ctx context.Context, person *Person, confirm bool) error",
"GetFunc func(ctx context.Context, id string) (*Person, error)",
"func (mock *PersonStoreMock) Create(ctx context.Context, person *Person, confirm bool) error",
"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*Person, error)",
"panic(\"PersonStoreMock.CreateFunc: method is nil but PersonStore.Create was just called\")",
"panic(\"PersonStoreMock.GetFunc: method is nil but PersonStore.Get was just called\")",
"lockPersonStoreMockGet.Lock()",
"mock.calls.Get = append(mock.calls.Get, callInfo)",
"lockPersonStoreMockGet.Unlock()",
"// ID is the id argument value",
}
for _, str := range strs {
if !strings.Contains(s, str) {
t.Errorf("expected but missing: \"%s\"", str)
}
}
}
func TestMoqExplicitPackage(t *testing.T) {
m, err := New("testpackages/example", "different")
if err != nil {
@ -69,6 +103,34 @@ func TestMoqExplicitPackage(t *testing.T) {
}
}
func TestMoqExplicitPackageWithStaticCheck(t *testing.T) {
m, err := New("testpackages/example", "different")
if err != nil {
t.Fatalf("moq.New: %s", err)
}
var buf bytes.Buffer
err = m.Mock(&buf, "PersonStore")
if err != nil {
t.Errorf("m.Mock: %s", err)
}
s := buf.String()
// assertions of things that should be mentioned
var strs = []string{
"package different",
"var _ example.PersonStore = &PersonStoreMock{}",
"type PersonStoreMock struct",
"CreateFunc func(ctx context.Context, person *example.Person, confirm bool) error",
"GetFunc func(ctx context.Context, id string) (*example.Person, error)",
"func (mock *PersonStoreMock) Create(ctx context.Context, person *example.Person, confirm bool) error",
"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*example.Person, error)",
}
for _, str := range strs {
if !strings.Contains(s, str) {
t.Errorf("expected but missing: \"%s\"", str)
}
}
}
// TestVeradicArguments tests to ensure variadic work as
// expected.
// see https://github.com/matryer/moq/issues/5

View File

@ -8,6 +8,7 @@ var moqTemplate = `// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package {{.PackageName}}
{{- $sourcePackagePrefix := .SourcePackagePrefix}}
import (
{{- range .Imports }}
@ -22,6 +23,10 @@ var (
{{- end }}
)
// Ensure, that {{.InterfaceName}}Mock does implement {{.InterfaceName}}.
// If this is not the case, regenerate this file with moq.
var _ {{$sourcePackagePrefix}}{{.InterfaceName}} = &{{.InterfaceName}}Mock{}
// {{.InterfaceName}}Mock is a mock implementation of {{.InterfaceName}}.
//
// func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) {

View File

@ -12,6 +12,10 @@ var (
lockServiceMockUser sync.RWMutex
)
// Ensure, that ServiceMock does implement Service.
// If this is not the case, regenerate this file with moq.
var _ dotimport.Service = &ServiceMock{}
// ServiceMock is a mock implementation of Service.
//
// func TestSomethingThatUsesService(t *testing.T) {

View File

@ -12,6 +12,10 @@ var (
lockServiceMockDoSomething sync.RWMutex
)
// Ensure, that ServiceMock does implement Service.
// If this is not the case, regenerate this file with moq.
var _ Service = &ServiceMock{}
// ServiceMock is a mock implementation of Service.
//
// func TestSomethingThatUsesService(t *testing.T) {

View File

@ -1,3 +1,4 @@
package somerepo
// SomeType is some type
type SomeType string