README
¶
ifacegen
Ifacegen generates skeleton code of a type to satisfy an interface. It
can be used to generate snippet that satisfies an interface, such as
sort.Interface, or generate mock struct in tests.
Ifacegen is intuitive to use. The interface is specified as
{package_import_path}.{interface_name},
e.g. google.golang.org/grpc.Compressor. The package can be a
vendored one, in GOPATH or GOROOT. {package import path}. is
optional. If no {package import path}. is specified, the
{interface_name} is looked up in the local package.
Different from other mock tools, such as gomock, ifacegen takes a minimalistic approach. Ifacegen does not introduce any DSL, and tries to generate code that is like manually written by developer.
Ifacegen generates the method stubs of a struct to satisfy the interface, but leave the actual code to mock the methods to developer. It is up to developer to decide how to verify the input and/or return the output.
Code Snippet
You can use ifacegen to generate method stubs of an interface.
For example, to implement sort.Interface of a type fooSlice, you run ifacegen to generate the method stubs,
ifacegen -r fooSlice -i sort.Interface
This generates the following code snippet and print to stdout,
func (m fooSlice) Len() int {
}
func (m fooSlice) Less(i int, j int) bool {
}
func (m fooSlice) Swap(i int, j int) {
}
Now you can fill in the implementation details of these methods.
Mock
Ifacegen can generate mock struct to satisfy an interface as well.
For example, to mock net.Conn, you run ifacegen to generate a mock struct,
ifacegen -i net.Conn -m -o netconn_mock_test.go
This generates a file netconn_mock_test.go with the code below,
// @generated by ifacegen
package main
import (
"net"
"sync/atomic"
"time"
)
const (
callClose = 0
callLocalAddr = 1
callRead = 2
callRemoteAddr = 3
callSetDeadline = 4
callSetReadDeadline = 5
callSetWriteDeadline = 6
callWrite = 7
)
type ConnMock struct {
PanicIfNotMocked bool
CloseMock func() error
LocalAddrMock func() net.Addr
ReadMock func(b []byte) (n int, err error)
RemoteAddrMock func() net.Addr
SetDeadlineMock func(t time.Time) error
SetReadDeadlineMock func(t time.Time) error
SetWriteDeadlineMock func(t time.Time) error
WriteMock func(b []byte) (n int, err error)
callCounts [8]int32
}
func (m *ConnMock) Close() (err error) {
atomic.AddInt32(&m.callCounts[callClose], 1)
if m.CloseMock == nil {
if m.PanicIfNotMocked {
panic("Close is not mocked")
}
return err
}
return m.CloseMock()
}
func (m *ConnMock) CloseCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callClose]))
}
func (m *ConnMock) LocalAddr() (r0 net.Addr) {
atomic.AddInt32(&m.callCounts[callLocalAddr], 1)
if m.LocalAddrMock == nil {
if m.PanicIfNotMocked {
panic("LocalAddr is not mocked")
}
return r0
}
return m.LocalAddrMock()
}
func (m *ConnMock) LocalAddrCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callLocalAddr]))
}
func (m *ConnMock) Read(b []byte) (n int, err error) {
atomic.AddInt32(&m.callCounts[callRead], 1)
if m.ReadMock == nil {
if m.PanicIfNotMocked {
panic("Read is not mocked")
}
return n, err
}
return m.ReadMock(b)
}
func (m *ConnMock) ReadCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callRead]))
}
func (m *ConnMock) RemoteAddr() (r0 net.Addr) {
atomic.AddInt32(&m.callCounts[callRemoteAddr], 1)
if m.RemoteAddrMock == nil {
if m.PanicIfNotMocked {
panic("RemoteAddr is not mocked")
}
return r0
}
return m.RemoteAddrMock()
}
func (m *ConnMock) RemoteAddrCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callRemoteAddr]))
}
func (m *ConnMock) SetDeadline(t time.Time) (err error) {
atomic.AddInt32(&m.callCounts[callSetDeadline], 1)
if m.SetDeadlineMock == nil {
if m.PanicIfNotMocked {
panic("SetDeadline is not mocked")
}
return err
}
return m.SetDeadlineMock(t)
}
func (m *ConnMock) SetDeadlineCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callSetDeadline]))
}
func (m *ConnMock) SetReadDeadline(t time.Time) (err error) {
atomic.AddInt32(&m.callCounts[callSetReadDeadline], 1)
if m.SetReadDeadlineMock == nil {
if m.PanicIfNotMocked {
panic("SetReadDeadline is not mocked")
}
return err
}
return m.SetReadDeadlineMock(t)
}
func (m *ConnMock) SetReadDeadlineCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callSetReadDeadline]))
}
func (m *ConnMock) SetWriteDeadline(t time.Time) (err error) {
atomic.AddInt32(&m.callCounts[callSetWriteDeadline], 1)
if m.SetWriteDeadlineMock == nil {
if m.PanicIfNotMocked {
panic("SetWriteDeadline is not mocked")
}
return err
}
return m.SetWriteDeadlineMock(t)
}
func (m *ConnMock) SetWriteDeadlineCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callSetWriteDeadline]))
}
func (m *ConnMock) Write(b []byte) (n int, err error) {
atomic.AddInt32(&m.callCounts[callWrite], 1)
if m.WriteMock == nil {
if m.PanicIfNotMocked {
panic("Write is not mocked")
}
return n, err
}
return m.WriteMock(b)
}
func (m *ConnMock) WriteCallCount() int {
return int(atomic.LoadInt32(&m.callCounts[callWrite]))
}
Now you can use ConnMock and set the interesting *Mock funcs in your tests. For example, to test Read,
func TestFoo(t *testing.T) {
conn := &ConnMock{
ReadMock: func(b []byte) (int, error) {
return copy(b, "hello"), nil
},
}
...
got := make([]byte, 10)
n, err := conn.Read(got)
...
}
Usage
Usage of ifacegen:
-i string
Interface name, [{import_path}.]{Interface}, e.g. net/http.Handler, Foo. (Required)
-m Generate mock struct if true
-o string
Name of output file, default to os.Stdout
-r string
Name of receiver, default to *{Interface}{Gen|Mock}
-t Put the mock struct in test package if true
where,
{import_path}is the package import path as specified in the import declaration, e.g.net/http,golang.org/x/crypto/nacl/box. The package can be a vendored one.{import_path}.is optinal. When{import_path}is not specified, the interface is searched in the local package.- if you want the receiver to be point receiver, prefix the name with
*, e.g.-r '*MyHandler'. The default receiver is point receiver. - if
-mis true, the mock struct is generated; otherwise code snippet is generated. The mock struct is in the local package. But if-tis true, the mock struct is in the{local_package}_testpackage.
Documentation
¶
Overview ¶
Ifacegen generates skeleton code of a type to satisfy an interface. For example, to generate code to satisfy sort.Interface,
ifacegen -r stringSlice -i sort.Interface
Ifacegen can generate mock struct of an interface as well by specifying a package name. For example,
ifacegen -p myhttp -o httphandler_mock.go -i net/http.Handler