- Notifications
You must be signed in to change notification settings - Fork2
Mocking DSL for golang that incorporates Gomega matchers.
License
xeger/gomuti
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Gomuti is DSL formocking Golang interfaces, inspired byGomega and drawing upon Gomega matchers to dispatch mock method calls.With aGinkgo-like DSL for programming mock behavior, Gomuti makes iteasy to write beautiful, well-isolated unit tests.
Mocks can also bespies and stubs,enablingbehavior-driven development andterse, easy-to-maintain mock setup.
Imagine you have an interface that you want to mock.
typeAdderinterface {Add(l,rint64)int64}
To properly mock this interface, you need to create a struct type that has thesame methods. The struct also holds two Gomuti-related fields that keep stateabout the programmed behavior of the mock and the observed method calls:
import gtypes"github.com/xeger/gomuti/types"typeMockAdderstruct {Mock gtypes.MockSpy gtypes.Spy }func(m*MockAdder)Add(l,rint64)int64 {m.Spy.Observe(l,r)r:=m.Mock.Call("Add",l,r)returnr[0].(int64) }
In reality you would useMongoose togenerate a mock type and methods for every interface in your package,but a hand-coded mock is fine for example purposes.
To program behavior into your mock, use the DSL methods in thegomuti
package.Allow()
instructs your mock to expect a method call andtells it what to return.
Imagine you're writing unit tests for theMultiplier
typeand you want to isolate yourself from bugs inAdder
.
import ( ."github.com/onsi/ginkgo" ."github.com/xeger/gomuti" )Describe("multiplier",func() {varsubject*multipliervaradderAdderBeforeEach(func() {adder=&MockAdder{}m:=&multiplier{Adder:a} })It("computes the product of two integers",func() {Allow(adder).Call("Add").With(5,5).Return(10)Allow(adder).Call("Add").With(10,5).Return(15)result:=subject.Multiply(3,5))Expect(result).To(Equal(15)) }) })
TheAllow()
DSL can use any Gomega matcher for method parameters and Gomutiprovides a few matchers of its own; together, these allow you to mocksophisticated behavior. Imagine your adder has a newAddStuff()
featurethat adds arbitrarily-typed values.
Allow(adder).Call("AddStuff").With(AnythingOfType("bool"),Anything()).Return(true)
You can use theHaveCall()
Gomega matcher to spy on your mock, verifying thenumber of calls actually made to your mock as well as the specific parametervalues.
integer:=AnythingOfType("int64")Expect(adder).To(HaveCall("Add").With(integer,integer).Times(2))
If you generate your mocks withMongoose,then they come with a booleanStub
field; setting this field to true causesall methods to return zero values unless a matching call has been programmed.
Gomuti has some method aliases that imitate RSpec's plain-English DSL.
Expect(adder).ToReceive("Add").With(42,Anything()).AndReturn(42)adder.Add(42,7)Expect(adder).To(HaveReceived("Add").Once())
Gomuti's long-form DSL uses concise English words as method names.There is also a short-form DSL built around the methodgomuti.Â()
. To producethe  character, typeAlt+0194
on Windows keyboards orShift+Option+M
on Mac keyboards(as a mnemonic, think "Â allows myMock theoption of being called.")
Short-form equivalents are provided forToReceive()
and other chained methods, anda super-terse form of  delivers maximum brevity. If we also use Gomega's Ω method, ourtests get very terse indeed. (Some would say "unreadable," but beauty is in the eye ofthe beholder.)
// Super terse DSLÂ(adder,"Add",5,5).Return(10)// Moderately terse DSL with complex matcher.big:=BeNumerically(">",2**32-1)Â(adder).Call("Add").With(big,Anything()).Panic("integer overflow")Ω(subject.Multiply(2,5)).Should(Equal(10))Ω(adder).Should(HaveCall("Add").Times(2))Ω(func() {subject.Multiply(2**32-1,1) }).Should(Panic())
Long and short method calls are interchangeable; even when using thelong-formAllow()
, we recommended usingCall()
instead ofToReceive()
because the word "receive" is usually associated with the channel-receiveoperation.
Check thefrequently-asked questions to see if your problem is common.
Make sure to checkGomuti's godocs for relevant information.
If you think Gomuti is missing a feature, check theroadmap to seeif a similar feature is already planned.
If you still need help,open an Issue.Clearly explain your problem, steps to reproduce, and your ideal solution (if known).
Fork thexeger/gomuti
repository on GitHub; make your changes; open a pull request.