Sunday, February 21, 2010

Mockito vs Mockachino

I wrote down some differences between Mockito and Mockachino, ordered by how important they are for actual mock usage.

Note that I am quite biased since I actually wrote Mockachino, but I'm also a great fan of Mockito and I still prefer Mockito over all other java mocking frameworks. I have tried to be as objective as possible, but if I have missed some important aspect to compare, please let me know, and I'll add it.

The basic syntax
The syntax is definitely one of the most important aspect of mocking, especially when comparing frameworks that are similar in most other regards.
Mockito and Mockachino have slight differences in syntax, with the biggest difference being when stubbing a mock method:

// Mockito
when(mock.theMethod(eq(value1), eq(value2), same(value3))
.thenReturn(theReturnValue);
// Mockachino
stubReturn(theReturnValue).on(mock).theMetod(value1, value2, same(value3));

Mockito has a better flow here: you first type what you want to match on and then what you want to return. Mockito also has a type safe return value, since the compiler will enforce that theReturnValue is of the same type as the return type of mock.theMethod().

There are a couple of disadvantages of this approach:
  1. It actually needs to invoke the mock first, and then undo the side effect it produces. This is actually impossible to do if the mock is actually a spy. What Mockito actually does here is remove the invocation from the mocks call history so it won't be a false match in any later verification.
  2. The mock invocation might actually throw an exception, which will kill the test. The workaround for this is to use Mockitos alternative syntax, which is more similar to Mockachinos. More in this problem later.
  3. It's not possible to use mocks inlined here, since that will confuse the stubbing mechanism, which basically just remembers the latest invoked mock when adding the stubbing.
Mockachino's approach may seem a bit backwards at first but it's generally not much more difficult to grasp than the difference between these sentences:
  1. When you call my by the phone number 08-123 456, I will send a fax reply back.
  2. I will send a fax reply back when you call me by the phone number 08-123 456.
Mockachino is a bit more consistent in its syntax here. Every kind of interaction with the mock (stubbing, adding observers, verifying behaviour) has the same syntax:

// Stubbing
stubReturn(theReturnValue)
.on(mock).theMetod(value1, value2, same(value3));
// Observing
observeWith(observer)
.on(mock).theMetod(value1, value2, same(value3));
// Verifying
verifyOnce()
.on(mock).theMetod(value1, value2, same(value3));
As you can see, they all end with
on(mock).theMetod(value1, value2, same(value3));
which is quite consistent. It also keeps the mock object close to the method call.
Compare it with Mockito, which breaks up this pattern by having additional parameters between the mock and the method call when verifying:
verify(mock, times(1)).theMetod(value1, value2, same(value3));

Clean stacktrace
Both Mockito and Mockachino clean up stacktraces upon errors, which means that the stacktrace will exclude all Mockito/Mockachino stack elements

Mixing argument matchers and plain arguments
When stubbing or verifying a method in Mockito, you may choose to use argument matchers instead of values, which gives you great flexibility. However, you can not mix them. The solution is simple: just add the eq()-matchers for everything that you don't want to match explicitly.

Mockachino has a slightly more friendly approach. It allows mixing plain values with matchers, as long as the plain values are not the default values for their type (i.e. null, false, 0, '\0').

In order verification
Mockito has a couple of bugs (or design choices) when trying to verify things in order. Here is one:

@Test
public void testInOrder() {
List mock = Mockito.mock(List.class);
mock.add("Foo");
mock.add("Bar");
mock.add("Foo");

InOrder order = Mockito.inOrder(mock);
order.verify(mock, Mockito.atLeast(1)).add("Foo");
order.verify(mock, Mockito.atLeast(1)).add("Bar");
order.verify(mock, Mockito.atLeast(1)).add("Foo");
}

This fails, even though it's clear that it shouldn't.
Compare with the Mockachino example below. This works as expected.

@Test
public void testMockachinoInOrder() {
List mock = Mockachino.mock(List.class);
mock.add("Foo");
mock.add("Bar");
mock.add("Foo");

InOrder order = Mockachino.verifyOrder();
order.verifyAtLeast(1).on(mock).add("Foo");
order.verifyAtLeast(1).on(mock).add("Bar");
order.verifyAtLeast(1).on(mock).add("Foo");
}
Singleton ordering per mock object
In Mockito, one mock object can only have one ordering-object. This means that the following does not work:

@Test
public void testMockito() {
List mock = Mockito.mock(List.class);

mock.add("Foo");

InOrder order1 = Mockito.inOrder(mock);
order1.verify(mock).add("Foo");

InOrder order2 = Mockito.inOrder(mock);
order2.verify(mock).add("Foo");
}

In Mockachino, each ordering object is different and holds its own verification state. This works as expected:

@Test
public void testMockachino() {
List mock = Mockachino.mock(List.class);

mock.add("Foo");

OrderingContext order1 = Mockachino.newOrdering();
order1.verify().on(mock).add("Foo");

OrderingContext order2 = Mockachino.newOrdering();
order2.verify().on(mock).add("Foo");
}

Multithreading
Mockito fails with incorrect error messages when trying to use the same mock in multiple threads.
With Mockachino, multithreading is not a problem. You can share mock contexts and even mocks between threads

equals, hashCode and toString
These three methods can be tricky, since they are base methods used a lot by Java standard libraries (Sets, Maps, Lists, et.c.). Mockachino supports stubbing of all these methods, Mockito only supports stubbing toString. Stubbing these methods can be very useful at times, such as using mocks as keys in maps where a correct equals and hashCode are essential.

When it comes to verifying, all these are possible to verify with Mockachino, but it's not always a good idea, since these methods can be called almost anywhere. Also, the correctness of your code should probably not depend on specific calls to these methods.

API that never lies

Mockito uses a generic VerificationMode parameter to the verify methods, but all verification modes do not work for InOrder verification. This is very unclear in the API.
Mockachino instead hides its unsupported modes in the ordering API.

Support for inline mocking
Since Mockito does a lot of dark magic to enable its terse syntax, it's quite frail when you interrupt its expected flow of constructs. Inline mocking is a perfect example of this.
I have on several occasions had the need to let a mock return another mock.

This, and similar constructs fails in Mockito:

@Test
public void testInlineMockito() {
List mock = Mockito.mock(List.class);
Mockito.when(mock.get(0)).thenReturn(Mockito.mock(List.class));
}

The workaround is at least simple:

@Test
public void testInlineMockitoWorkaround() {
List mock = Mockito.mock(List.class);
List secondMock = Mockito.mock(List.class);
Mockito.when(mock.get(0)).thenReturn(secondMock);
}

No workarounds are necessary with Mockachino since it does not rely on ordering of calls.
Thus, the equivalent in Mockachino works fine:

@Test
public void testInlineMockachino() {
List mock = Mockachino.mock(List.class);
Mockachino.stubReturn(Mockachino.mock(List.class)).on(mock).get(0);
}
Calling mock methods when verifying
Another interesting case is this. Due to Mockitos design choice of letting calls to verify and stub apply to the most recently invoked mock method, the following case breaks, since verify will actually try to verify mock.size() instead of mock.add()

@Test
public void testMockito() {
List mock = Mockito.mock(List.class);
mock.add(0);
Mockito.verify(mock).add(mock.size());
}

It works fine in Mockachino, due to a different design choice:

@Test
public void testMockachino() {
List mock = Mockachino.mock(List.class);
mock.add(0);
Mockachino.verifyOnce().on(mock).add(mock.size());
}

Deep mocks
Update 2010-03-13 - Both the latest Mockito and Mockachino have deep mock handlers that behave in the same way.

Time ranges Mockachino supports verifying that interactions with a mock happened in a specific time range.
See additional-features-of-mockachino for a more detailed explanation.
Mockito does not include this feature.

Saturday, February 13, 2010

Additional features of Mockachino

Mockachino is making good progress!
Apart from generic refactorings, I've added a few nifty features:

Support for equals, hashCode and toString
Unlike EasyMock and Mockito, Mockachino now supports stubbing, verifying of all these methods. The other mocking frameworks probaby have good reasons for not supporting those. I at least know that Mockachino used to have good reasons. If you're not interested in the technical details, you can skip the next two paragraphs.

All mocks need some sort of data storage for their metadata. The metadata is basically just a memory of all invocations and a list of all stubbing definitions. This metadata needs to either be stored in the mock itself or use some sort of mapping strategy. I used to have a WeakHashMap that mapped the mocks to their metadata, and for that to work I required a fixed equals and hashCode.

My new approach is instead to let all my mocks implement a secondary interface which has a secret method for retrieving the metadata. The invocation handler for the mock simply listens for this method call and returns its reference to the metadata. It's really quite simple, and as with all simple ideas, you start to wonder why you didn't think of it before.

The problem with in order verification
One problem I had was in order verification of this sort:

@Test
public void test() {
List mock = mock(List.class);
mock.add(100);
mock.add(200);
mock.add(100);

OrderingContext ordering = newOrdering();
ordering.verifyAtMost(1).on(mock).add(100);
ordering.verifyAtLeast(1).on(mock).add(200);
}

By reading the entire ordering part, it seems that the test would pass, since there is only one call to add(100) before the call to add(200). But at the time of the first verification, it doesn't know when it should stop looking for more matches. This is easy to see when considering the next example:

@Test
public void test() {
List mock = mock(List.class);
mock.add(100);
mock.add(100);

OrderingContext ordering = newOrdering();
ordering.verifyAtMost(1).on(mock).add(100);
}

Here you obviously expect a failure since there were in fact two calls to add(100) when you expected at most one. For this reason, Mockachino doesn't support "at most"-matching for in order verifications.

So I started thinking about different approaches.
You could do something like this instead:

@Test
public void test() {
List mock = mock(List.class);
mock.add(100);
mock.add(200);
mock.add(100);

OrderingContext ordering = newOrdering();
ordering.verifyAtMost(1).on(mock).add(100);
ordering.verifyAtLeast(1).on(mock).add(200);
ordering.verifyOrdering();
}

Simply change the ordering concept to not verify anything at all until the call to verifyOrdering() is called. At this point you do have all the information you need.
The problem with this is that it adds a lot of complexity, both to the code base and to the tests. It's similar to solving a complex regular expression - it would need to backtrack on failures until it can be sure that it's impossible to satisfy the conditions.

It's simply not a clean solution. In practice such an ordering tests would be frail and be far to dependent on the internal state.

Adding "points in time" and time range verification.
Another way of supporting these kind of use cases is to add two new very simple constructs, that should rarely be needed, but be very useful and powerful in the few cases that you do.

The first construct is the MockPoint. This is simply a point in time that you can get in two different ways:

// 1
MockPoint point = Mockachino.getCurrentPoint();

// 2
OrderingContext order = Mockachino.newOrdering();
order.verifyOnce().on(mock).add();
MockPoint point = order.afterLastCall();

With these points, you can take advantage of the second construct: between, after and before
Simply add between(point1, point2) before your verification line to limit your matches to calls done between those points in time.

So instead of checking that something happened at most a certain number of times in order, grab the time points and verify it normally with between instead:


@Test
public void test() {
List mock = mock(List.class);
mock.add(100);
mock.add(200);
mock.add(100);

// Get the points
OrderingContext ordering = newOrdering();
MockPoint p1 = ordering.atLastCall();
ordering.verifyAtLeast(1).on(mock).add(200);
MockPoint p2 = ordering.beforeLastCall();

between(p1, p2).verifyAtMost(1).on(mock).add(100);
}

It's not as pretty as in the first example, but it works and is conceptually simple.
I don't recommend overusing this feature since it's probably in most cases a warning sign that your code is frail and makes too many assumptions.

Friday, February 12, 2010

The different types of tests

There is a huge number of examples of types of tests in the development community and they can be categorized in many different ways

I am going to focus on splitting tests by their intention here.
I guess people generally think of tests as a tool for reducing bugs and keeping robustness. Tests give us the courage to dare perform large refactorings and introduce new features while being relatively confident that we aren't breaking things.

That's a very important part of writing tests but I'll argue that there's another side to it:
Tests help us design. Tests help us write clean code. Tests help us split code into isolated modules.

With these two in mind, consider the following two test strategys: Unit Testing and Blackbox Testing.

Blackbox tests
my definition:
A blackbox test looks at the code as if it were a black box, i.e. the internals of the system are unknown and irrelevant. You use your knowledge of the system requirements to provide the inputs and verify that the outputs are correct.

I really like writing blackbox tests because they are fairly immune to internal refactorings and can usually quite easily capture the requirements on a high level. Blackbox tests have the additional benefit of being able to test a lot of code at once, and only testing code that will actually be used by real users.

However, writing blackbox tests on a too high level doesn't force you to write clean and modularized code.

Unit tests
my definition:
A unit test verifies the correctness of individual components of the system (hence the name unit). If the component (or unit) needs some collaborators, you typically mock them, and let them provide the inputs you want for your specific test. Unlike black box testing, you want to limit the scope of testing as much as possible per test.

Unit tests on the other hand usually have to be rewritten every time you perform refactorings and they can usually only capture requirements that are contained within a single class. The advantage of unit tests is that they force you to write your classes to be testable individually, which greatly helps you write good code.

Coverage
Some people like to measure the coverage of their codebase, and diligently write unit tests until they're at an acceptable level. I think that writing unit tests for the sake of increasing coverage is wrong.

The problem is that you're potentially testing dead code, and our only way of detecting dead code is by looking at coverage reports.

Instead, consider measuring coverage from blackbox tests and unit tests separately.
The blackbox tests should reflect the overall system requirements so run coverage for those tests. Then by looking at the coverage report you can spot dead code - Code that isn't used by any requirement.

If you spot any particular dead code section, you have two options:
  1. Remove the code - it isn't used! Dead code bloats down your codebase.
  2. If the code can't be removed, it must be a part of some requirement, so formalize the requirement as a blackbox test and try it again.
If you try writing a unit test just to exercise that code, you haven't gained anything, just a false sense of code coverage.

Conclusion
When developing according to TDD practices, should you write blackbox tests or unit tests?
The answer is both! I like to start with writing blackbox tests that cover all the requirements I can come up with. Then continue iteratively with unit tests and code in the usual TDD cycle until both the blackbox tests and unit tests are happy.

This should mean that you both capture the necessary requirement while maintaining a healthy code base.

When mocks fail

A mocking framework has three fundamental features:
  1. Makes it easy to stub behaviour to make your test code work.
  2. Makes it easy to verify that some behaviour has taken place.
  3. Makes it easy to debug a broken test.
Today I'll focus on the third part.

When a test fails, it either means that your code is wrong or your test is wrong.
Either way, you want to find the cause of the problem as quickly as possible.

To assist with this, mocking frameworks try to give you as much relevant information as possible when a verification fails.

EasyMock usually says something like:
@Test
public void testFailEasymock() {
List mock = createNiceMock(List.class);
expect(mock.add("Hello")).andReturn(true);
replay(mock);
mock.remove("World");
mock.remove("Hello");
mock.add(null);
mock.add("World");
verify(mock);
}

java.lang.AssertionError:
Expectation failure on verify:
add("Hello"): expected: 1, actual: 0


which tells you that add was expected, but never called.

Mockito is a bit nicer and shows what was actually called instead:
@Test
public void testFailMockito() {
List mock = mock(List.class);
mock.remove("World");
mock.remove("Hello");
mock.add(null);
mock.add("World");
verify(mock, atLeastOnce()).add("Hello");
}

Argument(s) are different! Wanted:
list.add("Hello");
-> at ordering.MixedOrderTest.testFailMockito(MixedOrderTest.java:95)
Actual invocation has different arguments:
list.add(null);
-> at ordering.MixedOrderTest.testFailMockito(MixedOrderTest.java:93)

Expected :list.add("Hello");
Actual :list.add(null);

Which is more helpful than EasyMock.

However, Mockito only suggests the first invocation of list.add as the actual invocation instead of the best matching.

Mockachino goes a step further and suggests the three best matching calls, sorted by how well it was matched:
@Test
public void testFailMockachino() {
List mock = mock(List.class);
mock.remove("World");
mock.remove("Hello");
mock.add(null);
mock.add("World");
verifyAtLeast(1).on(mock).add("Hello");
}

se.mockachino.exceptions.VerificationError: Expected at least 1 call but got no calls
Method pattern:
add("Hello")

Near matches:
add("World")
at se.mockachino.order.InOrderTest.testFailMockito(InOrderTest.java:116)
add(null)
at se.mockachino.order.InOrderTest.testFailMockito(InOrderTest.java:115)
remove("Hello")
at se.mockachino.order.InOrderTest.testFailMockito(InOrderTest.java:114)
... skipping 1 calls

at se.mockachino.order.InOrderTest.testFailMockito(InOrderTest.java:117)

As you can see, both Mockito and Mockachino show where the verification call was made,
and where the actual matches were made. This is really helpful if you run the tests in an IDE, just click on the lines to jump to the corresponding line in the code.

It's clear that EasyMock shows too little information here, but how much is too much?

Is the simple approach of Mockito to just show the first partially matching method call sufficient? Yes, it probably does cover most of the cases but I think it would be improved without adding any noise if it tried to do some smarter matching.

I think it's equally likely that a mock called the wrong method but with the correct parameters compared to calling the correct method but with the wrong parameters. I think the approach of showing multiple suggestions is a good one.

In conclusion I think that both Mockito and Mockachino do a good job of reporting failed verifications, and that Mockachino may have an advantage in debugging some use cases where the mockito suggestion is the wrong one.

Tuesday, February 9, 2010

Injection and cyclic dependencies

Cyclic dependencies are bad, and they are usually a sign that one on more classes have too many responsibilities. Cyclic dependencies make your design rigid.

Finding the cycle
There are basically two ways cyclic dependencies can appear:
  1. You're using an injection framework such as Guice or Spring that automatically resolves cyclical dependencies without you knowing you even had them.
  2. You're using setters instead of constructors to initialize your classes.
The first case is easily exposed if you have suitable unit or scenario tests that are manually wired up.
The second case is simply bad practice. I really really advice you to use final fields and set them in the constructor. I can't begin to count the number of runtime issues I've had due to uninitialized fields.

So how do you resolve a cyclic dependency?
Resolving it is a much harder problem. You need to analyze your code and figure out what the cycle looks like, and what the root problem is.
Usually the problem is that one or more classes have too much responsibility and thus need many collaborators. Split up the classes in distinct responsibilities and remove dependencies you don't actually need.

Another option is to move some fields to methods instead and just pass along the collaborator you need. It's not always a good idea, but neither is keeping a large state inside a class.

Saturday, February 6, 2010

Followup on mocking frameworks for Java

So, a week has passed and my mocking framework is fairly complete for a first release. All the information can be found on http://code.google.com/p/mockachino/ I expect some slight API changes in the near future, adding a few more (but not many) features and fixing some bugs (though I have no known at this time).

I'd like to think that my experiment was a success, but how can I know how good it really is unless I get real users for it. It's a tricky situation. I personally think it has a better overall design than Mockito and mostly the same featureset, but generally you need to be significantly better for users to switch. I can't say I'm any different myself, why would I replace a library I use for a slightly better, if it would cost me time and effort to do so?

So there are a couple of issues I need to work on before I can have an actual userbase:

  1. Make it better than Mockito. This is by itself hard, since Mockito is already a very good mocking framework. Of all the mocking frameworks I've seen, it's by far superior. So I need to have all the features that Mockito has, plus a lot more.
  2. Figure out any realistic test usecases where Mockachino is better than Mockito. Given my knowledge of my own design and the design of Mockito, this should be doable to some extent at least.
  3. Make converting from Mockito to Mockachino easy. If you have a large codebase you don't want to manually rewrite all your tests to change framework. Maybe it is possible to write a small application that can convert existing java tests to use Mockachino instead of other frameworks (EasyMock, Mockito).
  4. Let people know it exists. This is hard. Word of mouth only goes so far. Some loose ideas include trying to make google rank the project site higher for relevant search terms, such as mocking and java. Also, I could inform tech bloggers that it exists so it can mentioned in articles that compare mocking frameworks.

Of course, the technical challenge is by itself worth something, and I definitely feel I have learned from it.

I guess I can sum up this entire entry in a single sentence.
If a code project falls in the internet forest and no one hears it, does it make a sound?