Mockery

Feb 8th, 2008 | By | Category: process

Mocking – Introduction

Objects are first rate citizens in the Java society. Like a typical society the Java world has different flavors of objects each performing its own function. The Single Responsibility principle (SRP) states that objects should perform one single responsibility to ensure maximum re-use. This principle, however sociologically sound poses huge testing challenges. The problem with it is that objects can no longer be tested in isolation. The entire dependency tree of objects needs to be materialized before an object can be tested.

Mocks are an attempt in the direction of faking object dependencies. The object being tested can be tested by mocking its immediate dependencies.

mockery.jpg

In the diagram above, for the object A to be tested, we need to materialize the entire chain of dependencies which means we need to create classes B,C,D and E. If one of the objects tested relies on the services of a container, then it becomes harder to test in the absence of a container.

Mock objects serve the following needs:

  • They mimic the behavior of normal objects so that the object being tested does not know that it is interacting with the mock object.
  • They mimic container behavior. A thinks it is interacting with a container but instead is interacting with an entire mock framework that apes what the container does.

In the example above, B and C would be mocked by mock objects. This ensures the following:

  • A can be tested without relying on containers.
  • The dependencies D and E dont have to be materialized since the mock objects B and C dont have dependencies of their own.

Strategies for Mocking

Writing Testable Classes.

A class that can be tested with mocks should be _testable_. This means that it has to allow the user of the class to replace an implementation of its dependencies with mock dependencies.

Conside the following class:

  1. public class A {
  2. public void foo(){
  3. B b = new B();
  4. // do something with B
  5. }
  6. }

This class is very difficult to test with mocks because it is instantiating B within a method. Hence we cannot replace B with a mocked instance of B.
To make this class testable it can be coded as follows:

  1. public class A {
  2.  
  3. public void foo(){
  4. B b = createB();
  5. // do something with B
  6. }
  7.  
  8. protected B createB() {
  9. return new B();
  10. }
  11. }

This version of the class is better but still not perfect. The reason that it is better is because it is possible to instantiate a sub class of A with the createB() method over-ridden.

  1. public class TestA extends TestCase {
  2. public void testFoo() {
  3. A a = createA();
  4. a.foo();
  5. }
  6.  
  7. public A createA(){
  8. return new A(){
  9. // over-ride createB() method in class A
  10. protected B createB() {
  11. // create a mock version of B and return.
  12. }
  13. }
  14. }
  15. }

The version of A that would be the most testable would be the one where B’s interface is used instead of the actual class B.

The most testable objects are the ones that use principles such as IOC (Inversion of Control) to facilitate the injection of dependencies in them.

How do mocks work

So what exactly is this mock object all about? How does it _ape_ what other objects do? They say “monkey say monkey do” and this is applicable to mocks as well. The following steps need to be followed in using mocks:

Create the mock object.

If the object to be mocked is a class(as opposed to an interface), it is possible that we might have to provide constructor arguments and values for using non default constructors.

Set the expectation.

This means that the mock object might have to be told as to what methods in it will be called, how many times they will be called and in what order. We also need to specify with what arguments the function would be called and how to match these arguments with the actual arguments passed.

Ex: Consider the following class:

  1.  
  2.  
  3. public class ClassToBeMocked {
  4. public ClassToBeMocked(String arg0){
  5. }
  6.  
  7.  
  8. public String method1(int arg0, String arg1) {
  9. }
  10.  
  11. public int method2(String arg0){
  12. }
  13. }
  14.  

This class needs a String argument to be instantiated. Accordingly that needs to be passed during the creation of the mock object phase.

In the set expectation stage, we can indicate that method1 would be called exactly once with arguments 10 and “foo” and method2 would be called twice exactly with arguments “bar”.

The way these expectations are set differs from one framework to another. The [JMock|http://www.jmock.org/getting-started.html] framework gives extensive control on argument matching.

For instance, see the [constraints|http://www.jmock.org/constraints.html] that can be set.

Set return Values

In this phase, we tell the mock object what value to return when the constraint is actually called. For instance, in the above example we can specify the mock object to return the string “John Doe” when method1 is called with arguments 20 and “foo”. We should also be able to say here that method1 should always return the string “John Doe” no matter what arguments are passed to it.

Actually execute the tests using the mock objects.

At this stage, the actual tests are run.

Verification

The mock objects may be explicitly called at this stage to verify if indeed they have been called with the correct number of arguments in the order specified.

The Denizens of the Mockery Zoo

A lot of frameworks exist for writing mocks. All of them rely on method interception which is achieved in Java in a couple of ways:

  • Code generation.
  • Interface and class interception.

Code generation is not a preferred approach since the code needs to be re-generated when the actual class changes. Also the test class needs to rely on mock code that has not been written (it is going to be generated in the build). Hence frameworks that utilize interface and class interception techniques are by far more popular in the world of mockist monks (yeah mocking is almost a religion in certain parts of the java landscape).

The two frameworks that have their own dedicated areas in the mockery zoo are:

  • JMock
  • EasyMock

Easymock scores due to its simplicity and its support for code completion. The following articles compare the two frameworks:

Here is the broad view echoed by these and other articles.

Feature: Documentation
JMock: Decent
EasyMock: Very good

Feature: Arguments matcher – i.e. the way we specify how arguments passed should be matched
JMock: Hard to use but extremely flexible.
EasyMock: Easy to use. Less flexible. But it is possible to create our own argument matchers if the need arises. Since in most cases, we dont need to use complicated argument matchers this should not be a limitation.

Feature: Code completions, Refactorings etc
JMock: Hard since the actual interface is not used in specifying the mock criteria
EasyMock: Works well with most IDEs since the actual interface is used

Feature: Ease of use and understanding
JMock: JMock is loved by the proponents of literate programming. This is because the expectation setting phase in JMock resembles a specification very closely. But to a developer, it is cumbersome to have to remember so many method calls and write this explicitly.
EasyMock: EasyMock is very easy to use since the actual method is called with the correct parameters during the expectation setting phase of preparing the mock.Since 2.2, EasyMock has become much more _literate_ also with effective use of generics and static imports.

Hence it is recommended that we use EasyMock for mock testing unless the flexibility provided by JMock over-rides the ease of use provided by EasyMock.

Infrastructure Support

Mock objects do a great job in infusing predictable behavior to the methods in classes and interfaces. However, certain classes require a lot of support from infrastructure.

Use the MockRunner framework for most of these classes.

Some of these classes are discussed below:

EJBs

Testing EJBs is usually pretty complicated. EJBs avail a lot of services from the container. Examples of this include:

  • Initialization and Destruction. (in the ejbCreate() and ejbRemove() methods)
  • Access to EJBSessionContext() and other context objects provided by the container.
  • Access to JNDISo there needs to be a framework of mock object that mimic the EJB container.

There is a separate project MockEJB for testing EJBs. It is still recommended to use Mockrunner though since Mockrunner has support for other varieties of classes as well.

JDBC DAO classes

Daos that utilize JDBC rely on services provided by the JDBC drivers and the chain of interfaces that arise from it. Hence objects such as ResultSet, PreparedStatement, Connection etc. need to be mocked as well.

Mockrunner scores here as well.

Struts Actions, Servlets,JMS etc.

The MockRunner framework also supports servlets, JMS and servlets. These classes do need a lot of support from infrastructure.

Deciding to Use Mock Objects

Mock objects are a powerful weapon in a unit tester’s arsenal, but sometimes it’s best not to use them. There are certain tests where mock objects are definitely not a good fit, the most obvious being acceptance and integration tests. While unit tests allow a developer to ensure that an object’s methods conform to a certain contract with the rest of the code, acceptance and integration tests are meant to test a system “end to end.” Replacing chunks of this system with an idealized version is not the best way to get accurate test results!

Summary

  • Most classes should be structured to be testable.
  • The Business Logic should be in POJO classes as opposed to artifacts that run on application servers. This would make the classes extremely testable and not be dependent on environment.
  • Easymock is good for testing POJOs.
  • For testing more complicated artifacts such as EJBs, JDBC DAOs etc. use Mockrunner.
Be Sociable, Share!

 Raja has been blogging in this forum since 2006. He loves a technical discussion any day. He finds life incomplete without a handy whiteboard and a marker.


Tags: ,

2 comments
Leave a comment »

  1. Hi

    Is there any way that I can pass constructor arguments while creating the Mock Objects using Jmock 2.X? If no, How can we pass the arguments of the constructor then?

    Thanks in advance

    Daisy

  2. <scratching-my-head-in-perplexity>
    @Daisy.. it has been a while since i wrote this article and hence to answer your question, I would have to do exactly what I would advocate you to do which is to look up the documentation. But JMock, i remember during that time, was an excellent framework and hence should support object creation using constructors as well as injection of dependencies using setter based strategies.

    But does JMock 2.x support it? Unfortunately, i can’t offhand answer that. But would love to see an update from you based on your research.

    Thanks
    </scratching-my-head-in-perplexity>

Leave Comment