Mocking

Filed Under Coding | 

A small introduction:

I've been writing a small piece of code recently. Since I'm test-infected, I cannot sleep well unless I've got test cases for everything I write. And I do use mock objects a lot - I test all my methods both in isolation.

Sometimes writing a piece of functionality as a static method is the right way to go. However, if I want to test a method that uses the static one, I can't isolate it! I was almost sick because of that breach in my solid testing strategy! I just had to solve it!

So, let's consider a simple static function:

 
public class Library {
    static public Map<String, String> getFileteredEnv() {
        Map<String, String> env = System.getenv();
        Map<String, String> retenv = new HashMap<String, String>();
        Set<String> keys = env.keySet();
        for(String key : keys) {
            if (key.length() &lt; 7) {
                retenv.put(key, env.get(key));
            }
        }
        return retenv;
    }
}

All it does is returning a list of environment variables which names have less than 7 characters. (Hey, it's just an example!)

So, there is a function which actually uses it. For the same of example, it's equally stupid:

 
public class ImportantClass {
    public int getSizeOfShortEnvironmentVariables() {
        Map<String, String> envs = Library.getFileteredEnv();
        return envs.size();
    }
}

So, since the static function relies on the current state of the environment on the machine I run the test, it seems I can't reliably test the non-static one. A mock is not just a whim. I'd say it's a necessity!

At first, I was thinking about hacking the class loader to intercept the request to load Library class and return a mock instead. Fortunately I invented the solution when I was driving and I couldn't code it right away. A couple hours later I sat in front of my computer and started with Google (instead of launching Eclipse right away).

What I found was just plain incredible. Watch this:

 
class MockupLibrary {
    static public Map<String, String> getFileteredEnv() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("Test", "ABC");
        map.put("Else", "def");
        return map;
        }
}

This is a mock version of the Library. It returns a controlled list of variables. Now, how do I put it in action?

 
@Before
public void setUp() {
    Mockit.redefineMethods(Library.class, MockupLibrary.class);
}

Isn't it cool? Thanks to JMockit (and java.lang.instrument), it is that simple! The simplicity and sheer coolness made me a fun of that library right away. A core of JMockit consists of a single class and a handful of methods. They do most of the job. And there are some nice features build upon it (like annotations).

And I guess I have to take a closer look at j.l.instrument. I just loooove this kinds of programming magic!

And, oh, BTW, you can redefine methods in a final class as well!


Comments

1 Comment so far

  1. guilty of untestability « monkey island on December 18, 2007 10:30 pm

    […] of untestability Posted December 18, 2007 Tomo writes how to mock static methods and how cool is JMockit. This gives me an opportunity to write about […]

Name (required)

Email (required)

Website

Speak your mind