Documentation ¶
Overview ¶
withmock is a tool to assist in mocking code for testing.
The basic idea is that you can mark import statements to indicate packages that should be mocked. Then, if you run your test via withmock then mock versions of the marked packages will be generated - and the tests will be run using those packages instead of the real ones.
Creating Mocks ¶
To mark an import for mocking, simply append a comment consisting of just the word mock to the end of the import line in the xxx_test.go file.
So if we had the import statement:
import ( "fmt" "os" "os/exec" "example.com/some/external/package" )
then we could mark the external package for mocking by changing it to:
import ( "fmt" "os" "os/exec" "example.com/some/external/package" // mock )
The mocking is not restricted to external packages. Though often we want to keep access to the original package for use in the test code itself. So, keeping the same example, we might want to use a mock version of fmt in the code under test. So, now we change the import to:
import ( "fmt" "os" "os/exec" mockfmt "fmt" // mock "example.com/some/external/package" // mock )
So, when run, the non-test code will be using the mocked fmt and external packages, and the test code will have the proper fmt, the mocked fmt as mockfmt, and the mocked external package using it's own name (which will assume it ext, for the purposes of this documentation).
Using Mocks ¶
The generated mock code behaves much like the code generated by gomock's mockgen , particularly when dealing with methods on types. Though there are some differences, due to the whole package nature.
The first thing to do with a mocked package is to set the controller. This needs to be done before any mocked method or function is called or expectation is set - otherwise the generated code will cause a panic. To set the controller, we use the special mock object returned by the MOCK() function, and call it's SetController method:
// Create a gomock controller, and arrange for it's finish to be called ctrl := gomock.NewController(t) defer ctrl.Finish() // Setup the mockfmt mock package mockfmt.MOCK().SetController(ctrl) // Setup the ext mock package ext.MOCK().SetController(ctrl)
Once you have set the controller then you can set your mock expectations, either using the EXPECT() function for function expectations, or the EXPECT() method for any method expectations. For example, if there was a type called UsefulType, and we were expecting it's HandyMethod to be called - followed by a message printed indicating the result, we might set our expectations as follows:
// Create a UsefulType instance ut := &ext.UsefulType{} // We expect to see HandyMethod called, and we want to return true ut.EXPECT().HandyMethod().Return(true) // And we expect to see our returned value printed mockfmt.EXPECT().Printf("HandyMethod returned: %v\n", true)
And then finally we can call our code under test, passing it our mocked UsefulType instance:
// And now, call the code under test importantFunction(ut)
Running the tests ¶
And now we just need to wrap our call to "go test", so we run:
withmock go test
and gomock and the Go testing framework will do the rest for us ... :D