Mock framework for java
For ease of use and increased readability in your tests, consider adding these static imports
import static se.mockachino.Mockachino.*;
import static se.mockachino.matchers.Matchers.*;
import static se.mockachino.Settings.*;
Now it's time to start writing your tests! This guide starts with the fundamentals all the way to the most advanced usage (which isn't really that advanced). Mockachino makes mocking simple. ##Basic usage Basic mock usage is easy
@Test
public void testExample() {
// Create a mock
List mock = mock(List.class);
// Interact with it
mock.get(123);
mock.get(456);
verifyOnce().on(mock).get(123);
verifyOnce().on(mock).get(456);
// Verify that some interactions never occured
verifyNever().on(mock).get(124);
}
Sometimes you need to setup your mocks to return values for the tested code to work. This is called stubbing.
@Test
public void testExampleStub() {
// Create a mock
List mock = mock(List.class);
// Stub a return value
stubReturn("Hello").on(mock).get(123);
// Interact with it
Object hello = mock.get(123);
Object shouldBeNull = mock.get(456);
assertEquals("Hello", hello);
assertEquals(null, shouldBeNull);
// Verify calls
verifyOnce().on(mock).get(123);
verifyOnce().on(mock).get(456);
}
As you might have noticed, the examples here uses a non generified list for simplicity. If you want to mock a generic class and not get warnings about type safety you need to use TypeToken
.
private static TypeToken<List<String>> LIST_TYPE_TOKEN = new TypeToken<List<String>>() {};
@Test
public void testExampleMockingGenerics() throws Exception {
// Create a mock
List<String> mock = mock(LIST_TYPE_TOKEN);
mock.add("Hello");
mock.add("World");
}
A matcher is something you can use instead of regular arguments when verifying or stubbing. A matcher makes it possible to verify interactions with parameters from a range of values.Here's a simple example
@Test
public void testExampleWithMatchers() {
// Create a mock
List mock = mock(List.class);
mock.add("Hello");
mock.add("World");
// Verify calls
verifyOnce().on(mock).add(eq("Hello"));
verifyExactly(2).on(mock).add(any(String.class));
}
eq()
is the most basic matcher, in fact all plain arguments get converted to an eq-matcher when verifying or stubbing. The any()
matcher is useful if you want to accept any object. The class parameter is just there to make the compiler happy.
The last defined stub will take precedence if multiple stubbers match, so you can set up default values-
@Test
public void testExampleStubOverride() {
// Create a mock
List mock = mock(List.class);
// Stub a return value
stubReturn("NullString").on(mock).get(anyInt());
stubReturn("Hello").on(mock).get(123);
// Interact with it
assertEquals("Hello", mock.get(123));
assertEquals("NullString", mock.get(1));
assertEquals("NullString", mock.get(2));
// Verify calls
verifyExactly(3).on(mock).get(anyInt());
}
It's possible to mix matchers and plain arguments in the same method verification or stubbing in most cases. The only exception is when the plain arguments is null
, 0
, false
or '\0'
. Here is how not to use it
@Test
public void testBadMatcherCombo() {
// Create a mock
List mock = mock(List.class);
// This works
verifyNever().on(mock).add(eq(0), any(Object.class));
// This doesn't
try {
verifyNever().on(mock).add(0, any(Object.class));
fail("This should never pass");
} catch (Exception e) {
e.printStackTrace();
}
}
The output:
se.mockachino.exceptions.VerificationError: Illegal mix of matchers and default values in the same method verification or stubbing. Replace null, 0, '\0' and false with matchers. at se.mockachino.unittests.ExamplesTest.testBadMatcherCombo(ExamplesTest.java:90)
If a verification fails, you'll get an informative output text.
@Test
public void testSimpleVerify() {
try {
List mock = mock(List.class);
mock.get(1);
mock.get(2);
mock.get(3);
verifyAtLeast(2).on(mock).get(3);
fail("This should never pass");
} catch (VerificationError e) {
e.printStackTrace();
}
}
The output:
se.mockachino.exceptions.VerificationError: Expected at least 2 calls, but got 1 call ACTUAL: mock.get(1) ACTUAL: mock.get(2) ACTUAL: (HIT) mock.get(3) EXPECTED: mock.get(3) at se.mockachino.unittests.ExamplesTest.testSimpleVerify(ExamplesTest.java:106)
##Verification in order It's easy to verify that calls arrive in a certain order, just create a new order object like this.
@Test
public void testInOrder() {
List mock = mock(List.class);
mock.add("Hello");
mock.remove("Hello");
mock.add("World");
mock.contains("Hello");
mock.add("Bar");
OrderingContext order = newOrdering();
order.verify().on(mock).add("Hello");
order.verify().on(mock).add("World");
order.verify().on(mock).contains("Hello");
order.verify().on(mock).add("Bar");
}
Spying is almost the same as mocking, the difference is that all method calls by default go through the spied on object. You can still stub away calls to objects if you want, so the spied object can be thought of as just the default stub for a mock. You spy on an object by providing both the interface (or class) that's relevant and then the actual object to spy on.
@Test
public void testSpy() {
// Setup spied object
ArrayList myList = new ArrayList();
myList.add("Real object");
// Create spy on object
List spy = spy(myList);
// Show that calls to the spy go to the real object
assertEquals(1, spy.size());
assertEquals("Real object", spy.get(0));
// Overwrite spy.get(0)
stubReturn("Fake object").on(spy).get(0);
spy.add("Real object 2");
// Show that the overwrite worked,
// but other calls still go through the real object
assertEquals(2, spy.size());
assertEquals("Fake object", spy.get(0));
assertEquals("Real object 2", spy.get(1));
// Verifying the calls still work of course
verifyExactly(2).on(spy).size();
verifyExactly(3).on(spy).get(anyInt());
verifyExactly(1).on(spy).add(any(Object.class));
}
Some matchers combines other matchers. The simplest example is Matchers.not
, which inverts a matcher. The matcher below matches compare("Hello", "World")
since mType(List.class)
does not match "Hello"
since it's not a list.
@Test
public void testNotMatcher() {
Comparator mock = mock(Comparator.class);
compare("Hello", "World");
compare("Foo", "Bar");
compare("Foo", null);
verifyOnce().on(mock).compare(not(mType(List.class)), "World");
}
Sometimes you want to catch the value that matches a specific matcher. That's really easy.
@Test
public void testSimple() {
List mock = mock(List.class);
ArgumentCatcher<Integer> catcher = ArgumentCatcher.create(mAnyInt());
mock.get(123);
verifyOnce().on(mock).get(match(catcher));
assertEquals(Integer.valueOf(123), catcher.getValue());
}
It's easy to add your own callback for mock method calls, for whichever reason. You can use matchers for designing what arguments to listen to, just as with stubbing and verifying. The example below shows how it's done.
@Test
public void testSimple() {
List mock = Mockachino.mock(List.class);
final List<String> list = new ArrayList<String>();
CallHandler listener = new CallHandler() {
@Override
public Object invoke(Object obj, MethodCall call) {
list.add(call.toString());
return null;
}
};
observeWith(listener).on(mock).get(123);
mock.get(123);
mock.get(124);
assertEquals(1, list.size());
assertEquals("get(123)", list.get(0));
}
You can of course stub a method to throw an exception instead of returning a value.
@Test
public void testException() {
try {
List mock = mock(List.class);
stubThrow(new ArrayIndexOutOfBoundsException("Hello")).on(mock).add(type(Object.class));
mock.add("");
fail("Should have thrown an exception");
} catch (Exception e) {
assertEquals("Hello", e.getMessage());
}
}
If you need complex behavior, you can implement your own answering strategy and plug into the mock.
@Test
public void testAnswer() {
List mock = mock(List.class);
stubAnswer(new CallHandler() {
@Override public Object invoke(Object obj, MethodCall call) {
Object first = call.getArguments()[0];
return first.toString() + first.toString();
}
}).on(mock).get(anyInt());
for (int i = 0; i < 100; i++) {
String s = "" + i;
String s2 = s + s;
assertEquals(s2, mock.get(i));
}
OrderingContext order = newOrdering();
for (int i = 0; i < 100; i++) {
order.verify().on(mock).get(i);
}
verifyExactly(100).on(mock).get(anyInt());
}