Gmock is a mocking framework for the Groovy language.
This documention describes the version 0.8 of Gmock which is compatible with Groovy 1.6.
import org.gmock.GMockTestCase
class LoaderTest extends GMockTestCase {
void testLoader(){
def mockLoader = mock()
mockLoader.load('key').returns('value')
play {
assertEquals "value", mockLoader.load('key')
}
}
}
The code under test should run through the play closure.
void testBasic(){
def aMock = mock()
// set up expectation
play {
// run your code
}
}
File mockFile = mock(File)
File mockFile = mock(File)
Strong typing works well with constructor call expectations:
File mockFile = mock(File, constructor("/a/path/file.txt"))
mockFile.getName().returns("file.txt")
play {
def file = new File("/a/path/file.txt")
assertEquals "file.txt", file.getName()
}
JavaLoader mock = mock(JavaLoader, invokeConstructor("loader"), constructor("name"))
def loader = mock()
loader.put("fruit").returns("apple")
play {
assertEquals "apple", loader.put("fruit")
}
Exceptions can be set up using the raises keyword.
def loader = mock()
loader.put("throw exception").raises(new RuntimeException("an exception")) // or 'raises(RuntimeException, "an exception")'
play {
def message = shouldFail(RuntimeException) {
loader.put("throw exception")
}
assertEquals "an exception", message
}
Property calls should be mocked using the following syntax. For Setters and getters
def loader = mock()
loader.name.set("a name")
loader.name.returns("a different name")
play {
loader.name = "a name"
assertEquals "a different name", loader.name
}
Support for exceptions and method stubs are similar to standard method calls. Ex:
def mockMath = mock(Math)
mockMath.static.random().returns(0.5)
play {
assertEquals 0.5, Math.random()
}
def controller = new SomeController()
def mockController = mock(controller)
mockController.params.returns([id: 3])
def mockRequest = mock()
mockController.request.returns(mockRequest)
Or you could use the shortcut version of it:
def controller = new SomeController()
mock(controller).params.returns([id: 3])
def mockRequest = mock()
mock(controller).request.returns(mockRequest)
This could be incredibly useful in the Grails environment, let's pick a simple tag lib:
class FakeTagLib {
def hello = { attrs ->
out << "hello"
}
}
We can mock the out property that way:
def tagLib = new FakeTagLib()
def mockTabLib = mock(tagLib)
def mockOut = mock()
mockTabLib.out.returns(mockOut)
mockOut << "hello"
play {
tagLib.hello()
}
Constructor calls are mocked using the following syntax:
def mockFile = mock(File, constructor("/a/path/file.txt"))
def mockFile = mock(File, constructor("/a/path/file.txt"))
mockFile.getName().returns("file.txt")
play {
def file = new File("/a/path/file.txt")
assertEquals "file.txt", file.getName()
}
You can expect an exception to be raised when a constructor call is matched:
def mockFile = mock(File, constructor("/a/path/file.txt").raises(RuntimeException))
play {
shouldFail(RuntimeException) {
new File("/a/path/file.txt")
}
}
Gmock lets you specify how many times an expectation can be called. Like here:
mockLoader.load(2).returns(3).atLeastOnce()
play {
assertEquals 3, mockLoader.load(2)
assertEquals 3, mockLoader.load(2)
}
The supported times matchers are:
mockLoader.put("test", match { it > 5 }).returns("correct")
play {
assertEquals "correct", mockLoader.put("test", 10)
}
Gmock is also fully compatible with the Hamcrest matcher. You will have to include the optional Hamcrest library in your classpath
Here is an example:
mockLoader.put("test", is(not(lessThan(5)))).returns("correct")
play {
assertEquals "correct", mockLoader.put("test", 10)
}
Here is an example of an hypothetic cached cat database.
def database = mock()
def cache = mock()
ordered {
database.open()
cache.get("select * from cat").returns(null)
database.query("select * from cat").returns(["cat1", "cat2"])
cache.put("select * from cat", ["cat1", "cat2"])
database.close()
}
def mockLock = mock()
ordered {
mockLock.lock()
unordered {
// ...
}
mockLock.unlock()
}
def mock = mock()
mock./set.*/(1).returns(2)
play {
assertEquals 2, mock.setSomething(1)
}
Gmock provides a few syntax shortcut useful in various situation.
Mock expectations could be setup during the mock creation in a closure. Like:
def mock = mock(Loader){
load(1).returns("one")
}
def mock = mock(Loader)
mock.load(1).returns("one")
Similarly to mock closure you can use the with syntax on mock. Like:
def mock = mock(Loader)
with(mock){
load(1).returns("one")
}
Static expectations could be setup using the static closure like:
def mockMath = mock(Math)
mockMath.static {
random().returns(.3)
random().returns(.6)
}
import org.gmock.WithGMock
...
@WithGMock
class YourTest extends GroovyTestCase {
// ... write your test here as normal
}
Alternatively we still provide the old way of defining a GMockController.
void testController(){
def gmc = new GMockController()
def mockLoader = gmc.mock()
mockLoader.load('key').returns('value')
gmc.play {
assertEquals "value", mockLoader.load('key')
}
}