Syntax Comparison - pobrelkey/mockdemo GitHub Wiki
This is a brief comparison of several major mock object libraries available for Java today.
The examples presented don't necessarily illustrate the sole correct way of writing tests using these libraries. They illustrate the way I've usually seen tests written with each library - your mileage may vary. The examples should be sufficient to give a flavor of differences in mocking syntax, and other relative strengths and weaknesses.
This article was inspired by Jean Tessier's "Mocking in Java: jMock vs. EasyMock".
I happen to be the author of Moxie. I wrote Moxie after I spent nearly three years on a project that used all four other libraries in this comparison, and got annoyed with all of them one reason or another. So I'm somewhat biased.
JMock 2 has had the most attention of the current crop of Java mocking libraries - it has had a large user base, and has been mentioned in numerous books (including Growing Object-Oriented Software Guided by Tests, written by JMock's authors). It was notable for having a mocking syntax designed to make sense as a domain-specific language (DSL). Proponents say its DSL is the most expressive API of any mocking library; critics say its mocking syntax as commonly used, involving the creation of an anonymous inner class per test, is excessively verbose.
JMock 2 should be considered a different library from its predecessor, JMock 1; its mocking syntax is almost entirely different.
The example code in this article was tested using JMock 2.5.1.
JMock 1 was my introduction to mocking around 2003. JMock 1 is generally considered a legacy library; new projects should use one of the other libraries in this article.
Compared to more modern mocking libraries, a major drawback of JMock 1 is that the code dates back to the JDK 1.3 days, and as such makes no attempt to use generics to provide a refactorable mocking syntax - i.e. one where using a refactoring tool to change method names/signatures will result in appropriate changes to mocking code. JMock 1's syntax, while quite nice for its time and more concise than that of JMock 2, is reflection-heavy - names of mocked methods are specified as strings, for example.
The example code in this article was tested using JMock 1.2.0.
Along with JMock 2, EasyMock is the other established mocking library for Java 1.5; its syntax is somewhat more concise than that of the two JMocks (especially JMock 2).
Uniquely among the major mocking libraries, EasyMock mocks are modal. That is to say, one programs the mocks with the expected behavior, then tells the mocks to "replay" their behavior before passing them to the code under test - so your mocks can either be in "record" mode or "replay" mode. Proponents say this makes it impossible to muddle together expectation-setting code and code that actually calls the code under test. Critics say that the required call to EasyMock.replay()
before calling the code under test is at best code clutter, at worst an abhorrence.
The example code in this article was tested using EasyMock 3.0, though it should also be valid for most of the EasyMock 2.x series. EasyMock 1.x had a different API.
Mockito is similar in API style to EasyMock (it started out as a fork of EasyMock), but takes a different approach to mocking: rather than setting up an exhaustive set of expectations ahead of time, you instead stub out any necessary behavior on your mocks, then after calling the code under test verify that the relevant methods on your mock objects were called.
Proponents of this "verification-driven" style say it makes tests less brittle and cuts down on the amount of meaningless boilerplate mock expectations in each test. Critics say it makes it more difficult to write tests that are as strict as traditional "expectation-driven" tests.
This article uses all expectation-driven tests - a testing style Mockito is ill-suited to writing - which makes it a not entirely fair comparison with respect to Mockito. The Mockito authors have an article on their wiki comparing verification-driven tests in Mockito with expectation-driven tests in EasyMock, which should give a flavor of the difference between the two styles.
The example code in this article was tested using Mockito 1.8.5.
JMockit is a lesser-known mocking framework for Java. It has its own syntax, most similar in appearance to JMock 2. It's capable of both expectation-driven and verification-driven testing.
Unlike most of the mocking frameworks in this comparison, I've never used JMockit in a real project; I wrote the example code you see below in about half an hour having just downloaded JMockit. I had previously found its syntax off-putting - with its use of anonymous inner classes, direct access to protected fields, and limited set of parameter matchers - and found little in my brief interactions with JMockit to dispel these notions. Also, it insists on being before JUnit in the classpath, which isn't a good sign.
The example code in this article was tested using JMockit 0.999.10.
Mockachino is a newish Java mocking framework. It takes Mockito's verification-driven approach to testing.
I've not used Mockachino in anger; the example code you see here is based on an original version kindly contributed by Kristofer Karlsson (Mockachino's author). Its syntax represents an improvement over Mockito. Personally I find the lack of a verifyNoMoreInteractions
method disturbing, as this means you won't be able to use Mockachino to write tests that blow up on unexpected method invocations - of course, if you're a believer in verification-driven testing you'll argue that you shouldn't be trying to write such tests to begin with.
The example code in this article was tested using Mockachino 0.6.
Moxie was written from scratch after years of annoyance experience with the four major frameworks, taking lessons from each. It aims to have a consistent, concise mocking syntax "nicer" than that of the competition.
The example code in this article was tested using Moxie 0.9.
Our example code will use mocks to test ROT13List
- a simple class that implements List<String>
, transforming the strings using the ROT13 algorithm when storing/retrieving them from an underlying List<String>
.
public class ROT13List extends AbstractList<String> {
private final List<String> delegate;
public ROT13List(List<String> delegate) {
this.delegate = delegate;
}
@Override
public String get(int index) {
return rot13(delegate.get(index));
}
@Override
public String set(int index, String element) {
return rot13(delegate.set(index, rot13(element)));
}
@Override
public void add(int index, String element) {
delegate.add(index, rot13(element));
}
@Override
public int indexOf(Object o) {
return delegate.indexOf(rot13((String) o));
}
@Override
public int lastIndexOf(Object o) {
return delegate.lastIndexOf(rot13((String) o));
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean contains(Object o) {
return delegate.contains(rot13((String) o));
}
@Override
public boolean add(String s) {
return delegate.add(rot13(s));
}
@Override
public boolean remove(Object o) {
return delegate.remove(rot13((String) o));
}
@Override
public String remove(int index) {
return rot13(delegate.remove(index));
}
@Override
public void clear() {
delegate.clear();
}
public static String rot13(String s) {
if (s == null) {
return null;
}
StringBuilder result = new StringBuilder();
for (char c : s.toCharArray()) {
if (c >= 'A' && c <= 'Z') {
result.append((char) ('A' + ((13 + c - 'A') % 26)));
} else if (c >= 'a' && c <= 'z') {
result.append((char) ('a' + ((13 + c - 'a') % 26)));
} else {
result.append(c);
}
}
return result.toString();
}
}
Tests using the different mocking libraries typically have different amounts of boilerplate code to enable mocking in the test. In the examples below, import statements are omitted for brevity.
This shows JMock 2.5.1 as used with JUnit 4. The JMock web site also has examples for using JMock 2 stand-alone and with JUnit 3.
@RunWith(JMock.class)
public class JMock2Test {
private JUnit4Mockery context = new JUnit4Mockery();
JMock 1 requires that you write your tests as JUnit 3 tests extending the JMock test base class.
public class JMock1Test extends MockObjectTestCase {
EasyMock has no out-of-the-box integration with JUnit, so EasyMock tests don't need any boilerplate code.
public class EasyMockTest {
Note that some people prefer to write their tests using an IMocksControl
instance - partly to give them finer-grained control over EasyMock's behavior, partly out of an aversion to calling static methods on the EasyMock
class. The most common pattern is to create this object in the setup method. For more about IMocksControl
, see the EasyMock documentation.
Mockito offers a MockitoJUnitRunner
for use with JUnit 4, which automatically puts a fresh mock object into each field annotated with @Mock
before each test. You can opt not to use this integration, in which case mock creation will look quite similar to the EasyMock examples.
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
@Mock
List<String> mock;
@Mock
List<String> otherMock;
When used as directed with JUnit 4 (including putting the JMockit jar ahead of the JUnit jar on the classpath), JMockit will automatically put a mock object into each field annotated with @Mocked
before each test.
public class JMockitTest {
@Mocked
private List<String> mock;
@Mocked
private List<String> otherMock;
Mockachino doesn't have any JUnit-specific integration features, but does have a convenient setupMocks
method that will put a mock into any field on the test class having a @Mock
annotation.
Also note that for one of our tests we'll need to manually implement a greaterThan
matcher as Mockachino doesn't have this built in. The code for this is included here for completeness - presumably you'll have this in a utility class in your project rather than on every test!
public class MockachinoTest {
@Mock
List<String> mock;
@Mock
List<String> otherMock;
@Before
public void setUp() throws Exception {
Mockachino.setupMocks(this);
}
private static Matcher<Integer> greaterThan(final int value) {
return new Matcher<Integer>() {
@Override
public boolean matches(Integer integer) {
return integer.intValue() > value;
}
@Override
public Class<Integer> getType() {
return Integer.class;
}
};
}
Moxie has MoxieRule
, usable under JUnit 4.7 or later. Like Mockito's JUnit integration, it automatically creates mocks before each test; unlike Mockito, it also verifies them afterward. Without MoxieRule
, manual mock creation/verification looks very similar to EasyMock.
An explanatory note: MoxieRule
also populates fields of type Group
; these are used to check that calls arrive in a sequence across mocks, and generally aren't needed otherwise.
public class MoxieTest {
@Rule
public MoxieRule moxie = new MoxieRule();
@Mock
private List<String> mock;
@Mock
private List<String> otherMock;
private Group sequence;
This test performs a few simple operations on ROT13List
, verifying that they are passed through appropriately to the underlying List
.
@Test
public void simpleScenario() {
final List<String> mock = context.mock(List.class);
context.checking(new Expectations() {{
one(mock).clear();
one(mock).add("Uryyb Jbeyq");
will(returnValue(true));
one(mock).size();
will(returnValue(1));
one(mock).get(0);
will(returnValue("Uryyb Jbeyq"));
}});
ROT13List underTest = new ROT13List(mock);
underTest.clear();
Assert.assertTrue(underTest.add("Hello World"));
Assert.assertEquals(1, underTest.size());
Assert.assertEquals("Hello World", underTest.get(0));
}
In JMock 2, mock expectations tend to be set on an anonymous subclass of JMock's Expectations
class. Expectations
contains most of the methods of JMock's domain-specific language. Note that these methods are all public
rather than protected
, so there's nothing preventing you from instantiating a run-of-the-mill (i.e. not an anonymous subclass) instance of Expectations
and calling methods on that to set up your mocks; the syntax seen here is usually used for brevity.
For those unfamiliar with this Java syntax, the code within the double braces is a Java instance initializer block - essentially a no-arg constructor for the anonymous subclass created in this method.
public void testSimpleScenario() {
Mock mock = mock(List.class);
mock.expects(once()).method("clear");
mock.expects(once()).method("add").with(eq("Uryyb Jbeyq")).will(returnValue(true));
mock.expects(once()).method("size").withNoArguments().will(returnValue(1));
mock.expects(once()).method("get").with(eq(0)).will(returnValue("Uryyb Jbeyq"));
ROT13List underTest = new ROT13List((List<String>) mock.proxy());
underTest.clear();
Assert.assertTrue(underTest.add("Hello World"));
Assert.assertEquals(1, underTest.size());
Assert.assertEquals("Hello World", underTest.get(0));
}
Note that nowhere in JMock 1's syntax does a call take place to the actual method being mocked; the method name is passed as a string. This means that refactoring tools will fail to update mock tests when method names or signatures change, resulting in broken tests.
@Test
public void simpleScenario() {
List<String> mock = EasyMock.createMock(List.class);
mock.clear(); // set expectation that the "clear" method will be called
EasyMock.expect(mock.add("Uryyb Jbeyq")).andReturn(true);
EasyMock.expect(mock.size()).andReturn(1);
EasyMock.expect(mock.get(0)).andReturn("Uryyb Jbeyq");
EasyMock.replay(mock);
ROT13List underTest = new ROT13List(mock);
underTest.clear();
Assert.assertTrue(underTest.add("Hello World"));
Assert.assertEquals(1, underTest.size());
Assert.assertEquals("Hello World", underTest.get(0));
EasyMock.verify(mock);
}
Note the distinctive feature of EasyMock's syntax: First calls are made to the mock to set the expectations. Then the call to EasyMock.replay()
signals that setup is finished, and that further calls on the mock are to be checked against the expectations.
@Test
public void simpleScenario() {
Mockito.stub(mock.add("Uryyb Jbeyq")).toReturn(true);
Mockito.stub(mock.size()).toReturn(1);
Mockito.stub(mock.get(0)).toReturn("Uryyb Jbeyq");
ROT13List underTest = new ROT13List(mock);
underTest.clear();
Assert.assertTrue(underTest.add("Hello World"));
Assert.assertEquals(1, underTest.size());
Assert.assertEquals("Hello World", underTest.get(0));
Mockito.verify(mock).clear();
Mockito.verify(mock).add("Uryyb Jbeyq");
Mockito.verify(mock).size();
Mockito.verify(mock).get(0);
Mockito.verifyNoMoreInteractions(mock);
}
You can probably see from this example why Mockito is ill-suited to writing exhaustive tests. To perform the equivalent of an expectation-driven test, every method called on the mock must be separately verified. (This is on top of any stubbing you need to perform ahead of time, leading to potentially two calls per method instead of one.) Furthermore, calls to unstubbed methods don't throw exceptions, making it difficult to track down places where unexpected calls occur.
Again, these examples aren't entirely fair on Mockito, which comes from a different philosophy of testing. Mockito fans would argue that trying to verify too many things as in this example makes your tests too broad and brittle, and your tests should instead take Mockito's lighter-weight approach of only verifying what you must.
@Test
public void simpleScenario() {
new Expectations() {{
mock.clear();
mock.add("Uryyb Jbeyq"); result = true;
mock.size(); result = 1;
mock.get(0); result = "Uryyb Jbeyq";
}};
ROT13List underTest = new ROT13List(mock);
underTest.clear();
Assert.assertTrue(underTest.add("Hello World"));
Assert.assertEquals(1, underTest.size());
Assert.assertEquals("Hello World", underTest.get(0));
}
JMockit's syntax looks similar to that of JMock 2, with an anonymous inner class extending JMockit's Expectations
class used to specify the expected calls.
Note that you specify the value that each mock call will return by assigning a value to the magical result
protected variable after the call (there is also a returns()
method you can call instead). Other protected fields are used to set invocation counts (i.e. number of times a method will be called) and for certain argument matchers, as will be seen later.
@Test
public void simpleScenario() {
Mockachino.when(mock.add(("Uryyb Jbeyq"))).thenReturn(true);
Mockachino.when(mock.size()).thenReturn(1);
Mockachino.when(mock.get(0)).thenReturn("Uryyb Jbeyq");
ROT13List underTest = new ROT13List(mock);
underTest.clear();
Assert.assertTrue(underTest.add("Hello World"));
Assert.assertEquals(1, underTest.size());
Assert.assertEquals("Hello World", underTest.get(0));
Mockachino.verifyOnce().on(mock).clear();
Mockachino.verifyOnce().on(mock).add("Uryyb Jbeyq");
Mockachino.verifyOnce().on(mock).size();
Mockachino.verifyOnce().on(mock).get(0);
}
As Mockachino is a verification-driven testing framework, most of the caveats about these examples not being entirely fair on Mockito will apply equally for Mockachino.
Note that Mockachino doesn't have a verifyNoMoreInteractions
method like Mockito, so unexpected method invocations on the mock won't fail the test.
@Test
public void simpleScenario() {
Moxie.expect(mock).will().clear();
Moxie.expect(mock).andReturn(true).on().add("Uryyb Jbeyq");
Moxie.expect(mock).andReturn(1).on().size();
Moxie.expect(mock).andReturn("Uryyb Jbeyq").on().get(0);
ROT13List underTest = new ROT13List(mock);
underTest.clear();
Assert.assertTrue(underTest.add("Hello World"));
Assert.assertEquals(1, underTest.size());
Assert.assertEquals("Hello World", underTest.get(0));
}
Mock expectations in Moxie begin by referencing the mock object, set up any details in the middle, and end with a call to the method concerned. The methods in the middle often have a few similarly-named equivalents which do exactly the same thing. (For example, the first statement uses will()
, while the rest use on()
.) The alternatives are provided to allow one to choose the method that "sounds" better depending on context or personal tastes.
Some people (especially EasyMock/Mockito fans) find it slightly stilted to have the method at the end of the mocking syntax. This was done to keep the syntax consistent for void and non-void methods - probably the biggest problem with EasyMock/Mockito's syntax.
Each mocking library has a mechanism by which conditional expressions can be evaluated against parameters to mocked methods. For example, we may want an expectation to match only if the value of a parameter is greater than zero, or if it is a string containing a certain substring. Alternately, we may not care what parameter gets passed to a method, and want the expectation to match regardless of the value passed.
@Test
public void fuzzyParameterMatching() {
final List<String> mock = context.mock(List.class);
context.checking(new Expectations() {{
one(mock).get(0);
will(returnValue("Tbbqolr Whcvgre"));
atLeast(1).of(mock).get(with(Matchers.greaterThan(0)));
will(returnValue("Uryyb Jbeyq"));
one(mock).add(with(Matchers.endsWith("Natryf")));
will(returnValue(true));
one(mock).add(with(Matchers.endsWith("Qrivyf")));
will(returnValue(false));
one(mock).set(with(any(Integer.TYPE)), with(Expectations.<String>anything()));
will(returnValue("Obawbhe Zrephel"));
}});
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("Goodbye Jupiter", underTest.get(0));
Assert.assertEquals("Hello World", underTest.get(1));
Assert.assertEquals("Hello World", underTest.get(19));
Assert.assertEquals("Hello World", underTest.get(90210));
Assert.assertTrue(underTest.add("California Angels"));
Assert.assertFalse(underTest.add("New Jersey Devils"));
Assert.assertEquals("Bonjour Mercury", underTest.set(0, "something"));
}
JMock 2's fuzzy match syntax largely revolves around Hamcrest matchers; the with()
method can be used to match parameters against an arbitrary Matcher
.
public void testFuzzyParameterMatching() {
Mock mock = mock(List.class);
mock.expects(once()).method("get").with(eq(0)).will(returnValue("Tbbqolr Whcvgre"));
mock.expects(atLeastOnce()).method("get").with(new IsGreaterThan(0)).will(returnValue("Uryyb Jbeyq"));
mock.expects(once()).method("add").with(new StringEndsWith("Natryf")).will(returnValue(true));
mock.expects(once()).method("add").with(new StringEndsWith("Qrivyf")).will(returnValue(false));
mock.expects(once()).method("set").withAnyArguments().will(returnValue("Obawbhe Zrephel"));
ROT13List underTest = new ROT13List((List<String>) mock.proxy());
Assert.assertEquals("Goodbye Jupiter", underTest.get(0));
Assert.assertEquals("Hello World", underTest.get(1));
Assert.assertEquals("Hello World", underTest.get(19));
Assert.assertEquals("Hello World", underTest.get(90210));
Assert.assertTrue(underTest.add("California Angels"));
Assert.assertFalse(underTest.add("New Jersey Devils"));
Assert.assertEquals("Bonjour Mercury", underTest.set(0, "something"));
}
JMock 1 had a Constraint
interface that fulfilled a similar function to Hamcrest's Matcher
interface. Unlike in JMock 2 and other mocking libraries, each parameter had to be specified as a Constraint
- you couldn't specify a bare value and presume that only parameters equal to that value would be accepted.
@Test
public void fuzzyParameterMatching() {
List<String> mock = EasyMock.createMock(List.class);
EasyMock.expect(mock.get(0)).andReturn("Tbbqolr Whcvgre");
EasyMock.expect(mock.get(EasyMock.gt(0))).andReturn("Uryyb Jbeyq").atLeastOnce();
EasyMock.expect(mock.add(EasyMock.endsWith("Natryf"))).andReturn(true);
EasyMock.expect(mock.add(EasyMock.endsWith("Qrivyf"))).andReturn(false);
EasyMock.expect(mock.set(EasyMock.anyInt(), EasyMock.<String>anyObject())).andReturn("Obawbhe Zrephel");
EasyMock.replay(mock);
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("Goodbye Jupiter", underTest.get(0));
Assert.assertEquals("Hello World", underTest.get(1));
Assert.assertEquals("Hello World", underTest.get(19));
Assert.assertEquals("Hello World", underTest.get(90210));
Assert.assertTrue(underTest.add("California Angels"));
Assert.assertFalse(underTest.add("New Jersey Devils"));
Assert.assertEquals("Bonjour Mercury", underTest.set(0, "something"));
EasyMock.verify(mock);
}
The EasyMock
class has many static methods that can be used to build match conditions - eq()
, lt()
, gt()
, isNull()
, and()
, or()
, not()
, etc. You can also specify custom match conditions by implementing EasyMock's IArgumentMatcher
interface.
@Test
public void fuzzyParameterMatching() {
Mockito.stub(mock.get(0)).toReturn("Tbbqolr Whcvgre");
Mockito.stub(mock.get(Mockito.intThat(Matchers.greaterThan(0)))).toReturn("Uryyb Jbeyq");
Mockito.stub(mock.add(Mockito.argThat(Matchers.endsWith("Natryf")))).toReturn(true);
Mockito.stub(mock.add(Mockito.argThat(Matchers.endsWith("Qrivyf")))).toReturn(false);
Mockito.stub(mock.set(Mockito.anyInt(), Mockito.<String>any())).toReturn("Obawbhe Zrephel");
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("Goodbye Jupiter", underTest.get(0));
Assert.assertEquals("Hello World", underTest.get(1));
Assert.assertEquals("Hello World", underTest.get(19));
Assert.assertEquals("Hello World", underTest.get(90210));
Assert.assertTrue(underTest.add("California Angels"));
Assert.assertFalse(underTest.add("New Jersey Devils"));
Assert.assertEquals("Bonjour Mercury", underTest.set(0, "something"));
Mockito.verify(mock).get(0);
Mockito.verify(mock, Mockito.atLeastOnce()).get(Mockito.intThat(new IsGreaterThan(0)));
Mockito.verify(mock).add(Mockito.argThat(Matchers.endsWith("Natryf")));
Mockito.verify(mock).add(Mockito.argThat(Matchers.endsWith("Qrivyf")));
Mockito.verify(mock).set(Mockito.anyInt(), Mockito.<String>any());
Mockito.verifyNoMoreInteractions(mock);
}
Mockito's fuzzy-match syntax is quite similar to EasyMock's, as Mockito started life as an EasyMock derivative. You can specify a custom Hamcrest Matcher
using Mockito's argThat()
method.
@Test
public void fuzzyParameterMatching() {
new Expectations() {{
mock.get(0); result = "Tbbqolr Whcvgre";
mock.get(with(0, Matchers.greaterThan(0))); result = "Uryyb Jbeyq"; minTimes = 1;
mock.add(withSuffix("Natryf")); result = true;
mock.add(withSuffix("Qrivyf")); result = false;
mock.set(anyInt, anyString); result = "Obawbhe Zrephel";
}};
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("Goodbye Jupiter", underTest.get(0));
Assert.assertEquals("Hello World", underTest.get(1));
Assert.assertEquals("Hello World", underTest.get(19));
Assert.assertEquals("Hello World", underTest.get(90210));
Assert.assertTrue(underTest.add("California Angels"));
Assert.assertFalse(underTest.add("New Jersey Devils"));
Assert.assertEquals("Bonjour Mercury", underTest.set(0, "something"));
}
JMockit has a limited set of parameter matchers that can be used directly; it seems the accepted practice for all but the simplest cases is to use the with()
method to specify a Hamcrest matcher. Note that there are two forms of with()
- the two-argument syntax (the first argument is a throwaway value) must be specified when matching a parameter of a primitive type.
@Test
public void fuzzyParameterMatching() {
Mockachino.when(mock.get(0)).thenReturn("Tbbqolr Whcvgre");
Mockachino.when(mock.get(Matchers.m(greaterThan(0)))).thenReturn("Uryyb Jbeyq");
Mockachino.when(mock.add(Matchers.endsWith("Natryf"))).thenReturn(true);
Mockachino.when(mock.add(Matchers.endsWith("Qrivyf"))).thenReturn(false);
Mockachino.when(mock.set(Matchers.anyInt(), Matchers.any(String.class))).thenReturn("Obawbhe Zrephel");
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("Goodbye Jupiter", underTest.get(0));
Assert.assertEquals("Hello World", underTest.get(1));
Assert.assertEquals("Hello World", underTest.get(19));
Assert.assertEquals("Hello World", underTest.get(90210));
Assert.assertTrue(underTest.add("California Angels"));
Assert.assertFalse(underTest.add("New Jersey Devils"));
Assert.assertEquals("Bonjour Mercury", underTest.set(0, "something"));
Mockachino.verifyOnce().on(mock).get(0);
Mockachino.verifyAtLeast(1).on(mock).get(Matchers.m(greaterThan(0)));
Mockachino.verifyOnce().on(mock).add(Matchers.endsWith("Natryf"));
Mockachino.verifyOnce().on(mock).add(Matchers.endsWith("Qrivyf"));
Mockachino.verifyOnce().on(mock).set(Matchers.anyInt(), Matchers.any(String.class));
}
Mockachino has a fuzzy-match syntax similar to Mockito or EasyMock, with several parameter matchers on its Matchers
utility class. Custom matchers can be specified with the m()
method; this takes an instance of Mockachino's Matcher
interface, which is similar in spirit to the interface of the same name in Hamcrest.
@Test
public void fuzzyParameterMatching() {
Moxie.expect(mock).andReturn("Tbbqolr Whcvgre").on().get(0);
Moxie.expect(mock).andReturn("Uryyb Jbeyq").atLeastOnce().on().get(Moxie.gt(0));
Moxie.expect(mock).andReturn(true).on().add(Moxie.endsWith("Natryf"));
Moxie.expect(mock).andReturn(false).on().add(Moxie.endsWith("Qrivyf"));
Moxie.expect(mock).andReturn("Obawbhe Zrephel").on().set(Moxie.anyInt(), Moxie.<String>anything());
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("Goodbye Jupiter", underTest.get(0));
Assert.assertEquals("Hello World", underTest.get(1));
Assert.assertEquals("Hello World", underTest.get(19));
Assert.assertEquals("Hello World", underTest.get(90210));
Assert.assertTrue(underTest.add("California Angels"));
Assert.assertFalse(underTest.add("New Jersey Devils"));
Assert.assertEquals("Bonjour Mercury", underTest.set(0, "something"));
}
Moxie's fuzzy-match syntax is similar to that of Mockito, including Hamcrest Matcher
support.
Most of the mocking libraries (except JMock 1) let you verify that method calls are received in a certain sequence across mocks. For example, you might want to verify that mock2.getBar()
is called only after a call to mock1.getFoo()
is received, and that mock3.getBaz()
is only called after the call to mock2.getBar()
.
@Test
public void callsInSequence() {
final List<String> mock = context.mock(List.class, "mock");
final List<String> otherMock = context.mock(List.class, "otherMock");
final Sequence sequence = context.sequence("some sequence name");
context.checking(new Expectations() {{
one(mock).add("svefg pnyy");
inSequence(sequence);
one(otherMock).add("frpbaq pnyy");
inSequence(sequence);
one(mock).add("guveq pnyy");
inSequence(sequence);
}});
ROT13List underTest = new ROT13List(mock);
ROT13List otherUnderTest = new ROT13List(otherMock);
underTest.add("first call");
otherUnderTest.add("second call");
underTest.add("third call");
}
Sequences across mocks are tied together using a Sequence
object.
public void testCallsInSequence() {
// You can't have sequences across mocks in JMock 1, so we'll only do this on one mock.
Mock mock = mock(List.class);
mock.expects(once()).method("add").with(eq("svefg pnyy")).will(returnValue(true)).id("alpha");
mock.expects(once()).method("add").with(eq("frpbaq pnyy")).after("alpha").will(returnValue(true)).id("beta");
mock.expects(once()).method("add").with(eq("guveq pnyy")).after("beta").will(returnValue(true));
ROT13List underTest = new ROT13List((List<String>) mock.proxy());
underTest.add("first call");
underTest.add("second call");
underTest.add("third call");
}
JMock 1 doesn't support call sequencing across mocks, but calls within a mock can be tied together if you give them ID's.
@Test
public void callsInSequence() {
IMocksControl control = EasyMock.createStrictControl();
List<String> mock = control.createMock(List.class);
List<String> otherMock = control.createMock(List.class);
EasyMock.expect(mock.add("svefg pnyy")).andReturn(true);
EasyMock.expect(otherMock.add("frpbaq pnyy")).andReturn(true);
EasyMock.expect(mock.add("guveq pnyy")).andReturn(true);
control.replay();
ROT13List underTest = new ROT13List(mock);
ROT13List otherUnderTest = new ROT13List(otherMock);
underTest.add("first call");
otherUnderTest.add("second call");
underTest.add("third call");
control.verify();
}
The EasyMock createStrictControl()
method gives you an IMocksControl
that verifies the sequencing of all calls across all mocks; there appears to be no way in EasyMock to verify the ordering of some calls and not others.
@Test
public void callsInSequence() {
ROT13List underTest = new ROT13List(mock);
ROT13List otherUnderTest = new ROT13List(otherMock);
underTest.add("first call");
otherUnderTest.add("second call");
underTest.add("third call");
InOrder ordering = Mockito.inOrder(mock, otherMock);
ordering.verify(mock).add("svefg pnyy");
ordering.verify(otherMock).add("frpbaq pnyy");
ordering.verify(mock).add("guveq pnyy");
}
In Mockito, the InOrder
object behaves similarly to a strict mock control in EasyMock.
@Test
public void callsInSequence() {
new Expectations() {{
mock.add("svefg pnyy");
otherMock.add("frpbaq pnyy");
mock.add("guveq pnyy");
}};
ROT13List underTest = new ROT13List(mock);
ROT13List otherUnderTest = new ROT13List(otherMock);
underTest.add("first call");
otherUnderTest.add("second call");
underTest.add("third call");
}
In JMockit, all calls set up within an individual instance of Expectations
are taken to be a sequence of calls across objects that must occur in the order specified.
@Test
public void callsInSequence() {
ROT13List underTest = new ROT13List(mock);
ROT13List otherUnderTest = new ROT13List(otherMock);
underTest.add("first call");
otherUnderTest.add("second call");
underTest.add("third call");
OrderingContext ordering = Mockachino.newOrdering();
ordering.verify().on(mock).add("svefg pnyy");
ordering.verify().on(otherMock).add("frpbaq pnyy");
ordering.verify().on(mock).add("guveq pnyy");
}
Mockachino uses the OrderingContext
object to perform ordered verifications on sequences of calls.
@Test
public void callsInSequence() {
Moxie.expect(mock).inGroup(sequence).will().add("svefg pnyy");
Moxie.expect(otherMock).inGroup(sequence).will().add("frpbaq pnyy");
Moxie.expect(mock).inGroup(sequence).will().add("guveq pnyy");
ROT13List underTest = new ROT13List(mock);
ROT13List otherUnderTest = new ROT13List(otherMock);
underTest.add("first call");
otherUnderTest.add("second call");
underTest.add("third call");
}
Moxie uses Group
s to tie together sequences of calls across mocks, similarly to JMock 2. (sequence
is a field of type Group
automatically populated by MoxieRule
, Moxie's JUnit 4 integration class.)
Configuring a mocked method to throw an exception rather than return a value is straightforward in most of the mocking libraries.
@Test
public void throwExceptions() {
final List<String> mock = context.mock(List.class);
context.checking(new Expectations() {{
one(mock).clear();
will(throwException(new RuntimeException("hello")));
one(mock).add(with(Matchers.containsString("Fdhveery")));
will(throwException(new RuntimeException("allergic to squirrels")));
}});
ROT13List underTest = new ROT13List(mock);
try {
underTest.clear();
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("hello", e.getMessage());
}
try {
underTest.add("Magic Squirrel Juice");
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("allergic to squirrels", e.getMessage());
}
}
public void testThrowExceptions() {
Mock mock = mock(List.class);
mock.expects(once()).method("clear").withNoArguments().will(throwException(new RuntimeException("hello")));
mock.expects(once()).method("add").with(contains("Fdhveery")).will(throwException(new RuntimeException("allergic to squirrels")));
ROT13List underTest = new ROT13List((List<String>) mock.proxy());
try {
underTest.clear();
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("hello", e.getMessage());
}
try {
underTest.add("Magic Squirrel Juice");
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("allergic to squirrels", e.getMessage());
}
}
@Test
public void throwExceptions() {
List<String> mock = EasyMock.createMock(List.class);
mock.clear(); // create expectation that clear() will be called
EasyMock.expectLastCall().andThrow(new RuntimeException("hello"));
EasyMock.expect(mock.add(EasyMock.contains("Fdhveery"))).andThrow(new RuntimeException("allergic to squirrels"));
EasyMock.replay(mock);
ROT13List underTest = new ROT13List(mock);
try {
underTest.clear();
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("hello", e.getMessage());
}
try {
underTest.add("Magic Squirrel Juice");
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("allergic to squirrels", e.getMessage());
}
EasyMock.verify(mock);
}
Note that EasyMock's syntax for throwing an exception from a mocked method returning void is inconsistent with that for methods that return a value.
@Test
public void throwExceptions() {
Mockito.doThrow(new RuntimeException("hello")).when(mock).clear();
Mockito.stub(mock.add(Mockito.contains("Fdhveery"))).toThrow(new RuntimeException("allergic to squirrels"));
ROT13List underTest = new ROT13List(mock);
try {
underTest.clear();
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("hello", e.getMessage());
}
try {
underTest.add("Magic Squirrel Juice");
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("allergic to squirrels", e.getMessage());
}
Mockito.verify(mock).clear();
Mockito.verify(mock).add(Mockito.contains("Fdhveery"));
Mockito.verifyNoMoreInteractions(mock);
}
As in EasyMock, Mockito's void-method syntax for throwing exceptions is also inconsistent with non-void methods - though it's slightly improved.
@Test
public void throwExceptions() {
new Expectations() {{
mock.clear(); result = new RuntimeException("hello");
mock.add(withSubstring("Fdhveery")); result = new RuntimeException("allergic to squirrels");
}};
ROT13List underTest = new ROT13List(mock);
try {
underTest.clear();
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("hello", e.getMessage());
}
try {
underTest.add("Magic Squirrel Juice");
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("allergic to squirrels", e.getMessage());
}
}
In JMockit, you make a mock method throw an exception by assigning the desired exception to the protected result
field immediately after the setup call. (The returns()
method can be used where a method actually returns an exception; no analogous throws()
method exists for those averse to directly setting fields.)
@Test
public void throwExceptions() {
Mockachino.stubThrow(new RuntimeException("hello")).on(mock).clear();
Mockachino.when(mock.add(Matchers.contains("Fdhveery"))).thenThrow(new RuntimeException("allergic to squirrels"));
ROT13List underTest = new ROT13List(mock);
try {
underTest.clear();
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("hello", e.getMessage());
}
try {
underTest.add("Magic Squirrel Juice");
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("allergic to squirrels", e.getMessage());
}
Mockachino.verifyOnce().on(mock).clear();
Mockachino.verifyOnce().on(mock).add(Matchers.contains("Fdhveery"));
}
Note that as in Mockito and EasyMock, the syntax to set up the raised exceptions is different depending on whether or not the method returns a value.
Kristofer Karlsson (Mockachino's author) points out that the following two lines would offer a more concise alternative to the try-catch blocks, though these would obviously lack the checks on the thrown exception:
Mockachino.assertThrows(RuntimeException.class).on(underTest).clear();
Mockachino.assertThrows(RuntimeException.class).on(underTest).add("Magic Squirrel Juice");
@Test
public void throwExceptions() {
Moxie.expect(mock).andThrow(new RuntimeException("hello")).on().clear();
Moxie.expect(mock).andThrow(new RuntimeException("allergic to squirrels")).on().add(Moxie.hasSubstring("Fdhveery"));
ROT13List underTest = new ROT13List(mock);
try {
underTest.clear();
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("hello", e.getMessage());
}
try {
underTest.add("Magic Squirrel Juice");
Assert.fail("should have thrown exception");
} catch (RuntimeException e) {
Assert.assertEquals("allergic to squirrels", e.getMessage());
}
}
Sometimes we want calls to a certain method to have a particular behavior, while ignoring them when it comes to determining whether the test passes or fails. The following test combines one checked mock expectation with one unchecked mock expectation.
@Test
public void ignoreInvocations() {
final List<String> mock = context.mock(List.class);
context.checking(new Expectations() {{
one(mock).get(0);
will(returnValue("Uryyb Jbeyq"));
ignoring(mock).add(with(Matchers.<String>anything()));
will(returnValue(true));
}});
ROT13List underTest = new ROT13List(mock);
Assert.assertTrue(underTest.add("doesn't"));
Assert.assertTrue(underTest.add("matter"));
Assert.assertTrue(underTest.add("it's all"));
Assert.assertTrue(underTest.add("ignored"));
Assert.assertTrue(underTest.add("anyway"));
Assert.assertEquals("Hello World", underTest.get(0));
}
Ignored mock calls are set up using the ignoring()
method.
public void testIgnoreInvocations() {
Mock mock = mock(List.class);
mock.expects(once()).method("get").with(eq(0)).will(returnValue("Uryyb Jbeyq"));
mock.stubs().method("add").with(ANYTHING).will(returnValue(true));
ROT13List underTest = new ROT13List((List<String>) mock.proxy());
Assert.assertTrue(underTest.add("doesn't"));
Assert.assertTrue(underTest.add("matter"));
Assert.assertTrue(underTest.add("it's all"));
Assert.assertTrue(underTest.add("ignored"));
Assert.assertTrue(underTest.add("anyway"));
Assert.assertEquals("Hello World", underTest.get(0));
}
"Stub" mock methods are created in JMock 1 using stubs()
.
@Test
public void ignoreInvocations() {
List<String> mock = EasyMock.createMock(List.class);
EasyMock.expect(mock.get(0)).andReturn("Uryyb Jbeyq");
EasyMock.expect(mock.add(EasyMock.<String>anyObject())).andReturn(true).anyTimes();
EasyMock.replay(mock);
ROT13List underTest = new ROT13List(mock);
Assert.assertTrue(underTest.add("doesn't"));
Assert.assertTrue(underTest.add("matter"));
Assert.assertTrue(underTest.add("it's all"));
Assert.assertTrue(underTest.add("ignored"));
Assert.assertTrue(underTest.add("anyway"));
Assert.assertEquals("Hello World", underTest.get(0));
EasyMock.verify(mock);
}
In EasyMock you can effectively "ignore" a method using the anyTimes()
modifier.
@Test
public void ignoreInvocations() {
Mockito.stub(mock.get(0)).toReturn("Uryyb Jbeyq");
Mockito.stub(mock.add(Mockito.<String>any())).toReturn(true);
ROT13List underTest = new ROT13List(mock);
Assert.assertTrue(underTest.add("doesn't"));
Assert.assertTrue(underTest.add("matter"));
Assert.assertTrue(underTest.add("it's all"));
Assert.assertTrue(underTest.add("ignored"));
Assert.assertTrue(underTest.add("anyway"));
Assert.assertEquals("Hello World", underTest.get(0));
Mockito.verify(mock).get(0);
}
There's no special way of setting up an "ignored" method in Mockito - you just don't verify it at the end of the test.
@Test
public void ignoreInvocations() {
new NonStrictExpectations() {{
mock.add(anyString); result = true;
}};
new Expectations() {{
mock.get(0); result = "Uryyb Jbeyq";
}};
ROT13List underTest = new ROT13List(mock);
Assert.assertTrue(underTest.add("doesn't"));
Assert.assertTrue(underTest.add("matter"));
Assert.assertTrue(underTest.add("it's all"));
Assert.assertTrue(underTest.add("ignored"));
Assert.assertTrue(underTest.add("anyway"));
Assert.assertEquals("Hello World", underTest.get(0));
}
The NonStrictExpectations
class is used to set "ignored" expectations which won't fail the test if they aren't fulfilled.
@Test
public void ignoreInvocations() {
Mockachino.when(mock.get(0)).thenReturn("Uryyb Jbeyq");
Mockachino.when(mock.add(Matchers.any(String.class))).thenReturn(true);
ROT13List underTest = new ROT13List(mock);
Assert.assertTrue(underTest.add("doesn't"));
Assert.assertTrue(underTest.add("matter"));
Assert.assertTrue(underTest.add("it's all"));
Assert.assertTrue(underTest.add("ignored"));
Assert.assertTrue(underTest.add("anyway"));
Assert.assertEquals("Hello World", underTest.get(0));
Mockachino.verifyOnce().on(mock).get(0);
}
As in Mockito, the way to "ignore" an invocation is to simply not verify it at the end of the test.
@Test
public void ignoreInvocations() {
Moxie.expect(mock).andReturn("Uryyb Jbeyq").on().get(0);
Moxie.stub(mock).andReturn(true).on().add(Moxie.<String>anything());
ROT13List underTest = new ROT13List(mock);
Assert.assertTrue(underTest.add("doesn't"));
Assert.assertTrue(underTest.add("matter"));
Assert.assertTrue(underTest.add("it's all"));
Assert.assertTrue(underTest.add("ignored"));
Assert.assertTrue(underTest.add("anyway"));
Assert.assertEquals("Hello World", underTest.get(0));
}
Moxie uses stub()
to set up "ignored" mock method behavior.
Once in a great while we'll want a mocked method to exhibit one behavior on one call, and another behavior on a subsequent call. The first mock expectation in the example returns a series of values across different calls, similar to an iterator method; the second expectation returns a value on the first call, then throws an exception on the second call.
@Test
public void consecutiveCalls() {
final List<String> mock = context.mock(List.class);
context.checking(new Expectations() {{
exactly(3).of(mock).get(0);
will(onConsecutiveCalls(returnValue("bar"), returnValue("gjb"), returnValue("guerr")));
exactly(2).of(mock).get(1234);
will(onConsecutiveCalls(returnValue("nqvbf"), throwException(new RuntimeException("blah blah"))));
}});
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("one", underTest.get(0));
Assert.assertEquals("two", underTest.get(0));
Assert.assertEquals("three", underTest.get(0));
Assert.assertEquals("adios", underTest.get(1234));
try {
underTest.get(1234);
Assert.fail("should have thrown an exception");
} catch (RuntimeException e) {
Assert.assertEquals("blah blah", e.getMessage());
}
}
JMock 2 uses the onConsecutiveCalls()
method to specify consecutive-calls behavior.
public void testConsecutiveCalls() {
Mock mock = mock(List.class);
mock.expects(exactly(3)).method("get").with(eq(0)).will(onConsecutiveCalls(returnValue("bar"), returnValue("gjb"), returnValue("guerr")));
mock.expects(exactly(2)).method("get").with(eq(1234)).will(onConsecutiveCalls(returnValue("nqvbf"), throwException(new RuntimeException("blah blah"))));
ROT13List underTest = new ROT13List((List<String>) mock.proxy());
Assert.assertEquals("one", underTest.get(0));
Assert.assertEquals("two", underTest.get(0));
Assert.assertEquals("three", underTest.get(0));
Assert.assertEquals("adios", underTest.get(1234));
try {
underTest.get(1234);
Assert.fail("should have thrown an exception");
} catch (RuntimeException e) {
Assert.assertEquals("blah blah", e.getMessage());
}
}
JMock 1 has its own similar version of the onConsecutiveCalls()
method.
@Test
public void consecutiveCalls() {
List<String> mock = EasyMock.createMock(List.class);
EasyMock.expect(mock.get(0)).andReturn("bar").andReturn("gjb").andReturn("guerr");
EasyMock.expect(mock.get(1234)).andReturn("nqvbf").andThrow(new RuntimeException("blah blah"));
EasyMock.replay(mock);
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("one", underTest.get(0));
Assert.assertEquals("two", underTest.get(0));
Assert.assertEquals("three", underTest.get(0));
Assert.assertEquals("adios", underTest.get(1234));
try {
underTest.get(1234);
Assert.fail("should have thrown an exception");
} catch (RuntimeException e) {
Assert.assertEquals("blah blah", e.getMessage());
}
EasyMock.verify(mock);
}
In EasyMock, consecutive-calls behavior is specified by calling multiple behavior-specifying methods in a row.
@Test
public void consecutiveCalls() {
Mockito.when(mock.get(0)).thenReturn("bar", "gjb", "guerr");
Mockito.when(mock.get(1234)).thenReturn("nqvbf").thenThrow(new RuntimeException("blah blah"));
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("one", underTest.get(0));
Assert.assertEquals("two", underTest.get(0));
Assert.assertEquals("three", underTest.get(0));
Assert.assertEquals("adios", underTest.get(1234));
try {
underTest.get(1234);
Assert.fail("should have thrown an exception");
} catch (RuntimeException e) {
Assert.assertEquals("blah blah", e.getMessage());
}
Mockito.verify(mock, Mockito.times(3)).get(0);
Mockito.verify(mock, Mockito.times(2)).get(1234);
Mockito.verifyNoMoreInteractions(mock);
}
Mockito specifies consecutive-calls behavior similarly to EasyMock, but also offers a shorthand method to specify different values to be returned from a method in succession.
@Test
public void consecutiveCalls() {
new Expectations(){{
mock.get(0); returns("bar", "gjb", "guerr"); times = 3;
mock.get(1234); result = "nqvbf";
mock.get(1234); result = new RuntimeException("blah blah");
}};
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("one", underTest.get(0));
Assert.assertEquals("two", underTest.get(0));
Assert.assertEquals("three", underTest.get(0));
Assert.assertEquals("adios", underTest.get(1234));
try {
underTest.get(1234);
Assert.fail("should have thrown an exception");
} catch (RuntimeException e) {
Assert.assertEquals("blah blah", e.getMessage());
}
}
JMockit offers a varargs version of the returns()
method to specify a series of values to be consecutively returned. Expectations that throw a series of exceptions, or exceptions after successfully returned values, have to be written out longhand.
@Test
public void consecutiveCalls() {
Mockachino.when(mock.get(0)).thenReturn("bar", "gjb", "guerr");
Mockachino.when(mock.get(1234)).thenReturn("nqvbf").thenThrow(new RuntimeException("blah blah"));
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("one", underTest.get(0));
Assert.assertEquals("two", underTest.get(0));
Assert.assertEquals("three", underTest.get(0));
Assert.assertEquals("adios", underTest.get(1234));
try {
underTest.get(1234);
Assert.fail("should have thrown an exception");
} catch (RuntimeException e) {
Assert.assertEquals("blah blah", e.getMessage());
}
Mockachino.verifyExactly(3).on(mock).get(0);
Mockachino.verifyExactly(2).on(mock).get(1234);
}
The consecutive-calls syntax for Mockachino is similar to that for Mockito.
@Test
public void consecutiveCalls() {
Moxie.expect(mock).andConsecutivelyReturn("bar", "gjb", "guerr").times(3).on().get(0);
Moxie.expect(mock).andReturn("nqvbf").andThrow(new RuntimeException("blah blah")).on().get(1234);
ROT13List underTest = new ROT13List(mock);
Assert.assertEquals("one", underTest.get(0));
Assert.assertEquals("two", underTest.get(0));
Assert.assertEquals("three", underTest.get(0));
Assert.assertEquals("adios", underTest.get(1234));
try {
underTest.get(1234);
Assert.fail("should have thrown an exception");
} catch (RuntimeException e) {
Assert.assertEquals("blah blah", e.getMessage());
}
}
Moxie's consecutive-calls syntax is similar to that of Mockito. Note that the total number of calls does not need to be explicitly specified, but if it is it will be validated against the number of consecutive-call behaviors.