How Does JMock work?

12 Sep

JMock is a very clean mocking framework. There are many others out there, but after I read “Growing Object Oriented Software Guided by Tests” I really prefer JMock for the most tasks. We talked about Java’s Proxy class in my last entry. This class – together with reflections – makes it possible to build a project like JMock.

JMock is rather complex. So let’s do our own very small Mocking framework. We won’t cover all JMock features. We ignore things like sequences and states. We won’t even generate nice error messages. But when we understood the basics, it won’t be hard to add them.

Again, there is a project on github which contains the full project. We will talk about the important ideas step by step and create a tiny mocking framework on the way.

Step 1: Defining our Test

We start with the user side of our library. Let’s assume we have an interface (we won’t be able to mock normal classes, see the last posting for an explanation) and some tests that use this interface.

Let’s go through the tests step by step: The first one defines two expected calls and calls the mock three times. We expect an error and default values as return values. If you want to build your own framework, this is enough for the first steps. We cover a bit more here but I will try to keep it simple.

The second tests adds the feature of “programmed” return values while the third one adds parameters to the expected calls. The fourth test calls the mock only once, but two calls are expected. The last test expects our Framework to simulate an exception.

Take a moment to understand what the tests do – they are the most important part here. What would you expect the framework to do?

Step 2: The two Proxies

One of the trickiest parts is the first test: how do we program our mock? If we take a closer look, we see that there are two situations where the mock object is used. One is the moment when a mock is programed (the part that start’s with “ oneOf”). The other is the moment when we call methods on the mock as part of the test.

There are multiple ways to build a mocking framework. One typical works this way:

  • Create a mock
  • Call all expected Methods on the Mock
  • Replay” or „rewind“ the mock
  • Execute the Test
  • Check whether the recorder methods and the invocations in the test were the same

But we’re taking another approach here, as we don’t really call the mock’s methods twice. Instead, we use two proxies. One is used to program the mock; it is returned when we call oneOf. The other one is the real mock object which later checks its invocations. oneOf is defined as

but it does not simply return mock but an object to program mock. Read the text again and think about it. The trick is essential for the rest of this tutorial. That said we can start our <tt>MockContext</tt> class.

The Context Class

We come back to the oneOf method in a moment, but the two proxy objects are even created earlier, in the MockContext:

 There are a few new classes here, we will visit them one by one. We keep all mocks saved in a Map. The key is the mock itself. The value is just a container. Every mock object has a name. We can also skip the name and use the name of the interface. The ExpecationList is a list of expected invocations. One proxy fills this list, the other one consumes it. The two proxies are created identically. We cover the rest of MockContext later. Let’s first make sure that the MockObjectContext is really just a container:

 Yep, it is.

The ProgrammableInvocationHandler

The proxies are harder to get. We start with a common baseclass for both proxies, the AbstractInvocationHandler:

 It stores a few properties and makes sure that our invoke method doesn’t have to handle null values. That’s all. The proxy which is used to program the mock is also a simple one. Here’s the ProgrammableInvocationHandler:

We forward calls to our expectationList. But what does the return value mean?

Take a look at the tests: we’re actually calling the methods after we use oneOf to receive our objects. So we have to provide a return value! Couldn’t we just return null? Well – yes and no. The result is not important, but if the mocked method has a primitive type as return value, Java throws a NullPointerException since it tries to unbox null. So we write a simple method that returns null for Object, 0 for ints, 0f for floats and so on:

 Java supports autoboxing, so we don’t have to write Integer.valueOf(0) here.

The MockInvocationHandler

Our mock object is more complex. To save us from exceptions when we work with the object, we define some fallbacks for the methods toString, hashCode and equalsTo. This seems a little bit quick and dirty and leaves much room for improvements. But nothing is harder as a NullPointerException that is raised while some other framework like JUnit tries to build up a helpful error message. This leads us to the following concept:

  • If a call is received check if there is a programmed expectation
  • If there is an expectation, return its programmed value
  • Otherwise, check if it is a call to toString, hashCode or equalsTo and return default values
  • If nothing matches, throw an Exception

The class looks like this (again we assume that some of the logic happens in our AssertionList):

And this is the formatCall method of MockUtils:

Well, this was hard stuff. I suggest again taking a break and re-read the whole stuff. Next we will glue it all together.

Step 3: Defining Expectations

So far we created two proxies per mock. The proxies are connected through a ExpecationList. We will now return to the MockContext class and make the mock programmable.

We already saw this object in our tests. The class provides a fluent interface to a potential mocking DSL. We provide three methods here: oneOf, willReturn and willThrow:

willReturn and willThrow are methods that are invoked without any context (this is typical for fluent DSLs), so we have to memorize the mock in the background. This is done by lastMock. willResult and willThrow just forward the calls (the ExpectationList class seems to bet big :-/). oneOf first checks whether the provided object really is a mocked object. If it is one, there’s a MockObjectContext in our map which we ask for the programmable proxy.

I think it’s time that we face the ExpectationList class. We build it in two steps. First, the programming part:

expectCall is called by a proxy, while the two add methods are called from our builder. As there is one list per mock, we can simply store all invoked methods together with their arguments in a list. Note that we also store the result value. We begin by saving the default value of that type (we already used this mechanism in the programmable proxy). So when neither willReturn nor willThrow is called, we just return some kind of or null value. The add methods overwrite this result with custom values. Let’s see how they look like. These are the three classes:

The get-method is called in MockInvocationHandler#invoke. To be able to see it all in action we need very few more methods.

Step 4: Checking Expectations

There are two tasks here:

  1. Checking whether an invocation is valid
  2. Checking whether all expected invocations happened

In Step 2 we already called a not yet defined method on our ExpectationList; it was called registerCall. Its task is to mark an expectation as “seen” (we just remove it from the list) and provide the result.

The Expectation#matches method looks like this:

The second point is done by checking all ExpectationList objects. If all of them are empty, all expected calls happened. This is done in the context class again:

And this is the final snipped in the ExpectationList class:

In summary, we did the following:

  • We create two proxy objects per mock
  • The first one fills the list of expectations
  • The second one is the real mock that checks the list of expectations
  • We created a small fluent interface to act with the first mock
  • We verify that every method is called

This stuff is really hard and sometimes confusing, but it 100% pure java with no additional tricks. The next tutorial (it will be very short compared to this one, I promise) shows how to add hamcrest matchers to the library.

One thought on “How Does JMock work?

  1. Pingback: How Does JMock work? (2/2) | JoWiSoftware

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.