Unit tests: there are people out there surviving without, but in many cases you want to have this life insurance. Something to protect you from slipping an error, something to accompany your software also when you will have long forgotten it and someone else will have to figure out how to maintain that legacy thing.

Why Mocking

If you want (need?) to write unit tests, by definition they have to test in isolation the behavior of a small unit (typically a class). The behavior of the tested method should not depend on the behavior of some other class because:

  • the other classes will change (impacting our test),
  • because the other class is not predictable (random generator, user input),
  • because it depends on external elements (network, databases,other processes),
  • because the other classes could require a complex initialization, and you do not want to do that

The unit test should reply to the question:

Does my unit work in an ideal world, surrounded by extremely nice and well behaving neighbours?

Mocks provide that ideal world. You can try the luck of your system in the ideal world using other kinds of tests (like integration tests).

The Argument that Mocking is a Bad Thing

Some people argue that you should not use mocks, because you should build your systems in such a way that make mocking not necessary.

I think this is partially true: if a system is well designed, with testability in mind from day 0, probably it will require much less mocking than otherwise. However you will still need mocking for three reasons:

  • you will inherit systems which either have no tests or have a low coverage. If tests are added as an afterthought the system is not designed to be testable and you will end up using a lot of mocking
  • it is true that in most situation you can avoid using mocking if you build your system using a lot of interfaces and dependency injection. However it means in most cases to use a fair amount of overengineering. You will end up having all over the places interfaces like FooBarable, BarFooator, and then classes like DummyFooBarable, HttpFooBarable, etc. Good, now you can avoid mocking but your system is became one of the reasons why other programmers laugh at Java code
  • sometimes your unit is a method, not a class, so you want to mock the rest of the class (partial mocking). Suppose you want to test method foo of class Foo. This method invoke bar and baz of the same class. If these methods interact with a lot of other classes (Bazzator, Bazzinga, BazLoader) it could be easy to just mock the methods bar and baz instead of mocking these other classes. Another advantage is that it make your tests more readable: you could write something like when this.bar() return 3 than this.foo() should return false instead of building a complex test to create the conditions under which this.bar() return 3

So, yes, you should not be mocking all the times, but many times you do not have an alternative. And in some cases the alternative is way worse.

Mocking Basics

Ok, let’s start by specifying our dependencies. We will use both Mockito and Easymock together with PowerMock for extra power. PowerMock complements both of Mockito and Easymock.

<!-- Note that this is used by PowerMock and it has to be placed on top,
 otherwise an older version is use and all the hell break loose,
 at least in my environment. Hopefully you do not need this -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.19.0-GA</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.easymock</groupId>
    <artifactId>easymock</artifactId>
    <version>3.3.1</version>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-easymock</artifactId>
    <version>1.5.6</version>
    <scope>test</scope>
</dependency>     
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>1.5.6</version>
    <scope>test</scope>
</dependency>

My Scenario

I had to work with a legacy application: you know, the kind of application that one wants to touch even with a pole, the one with all the original authors disappeared (deported for their crimes?). You get the picture.

Now we had to do a tiny change to this application and then run away like hell. Given we are good professionals we wanted to write a test: the problem was that our change was inside a very large method which was private and static. The method is named dealsToDisplay. Given it is private and static we invoke it through reflection (see invokeDealsToDisplay()). The actual tests are in dealsToDisplayNoBlacklistingTest, dealsToDisplaySomeBlacklistingTest, dealsToDisplayCompleteBlacklistingTest. All the rest is mocking and plumbing.

    @RunWith(PowerMockRunner.class)
    @PrepareForTest( { CatalogService.class, Logger.class, URLEncoder.class, ServiceClient.class})
    public class CatalogServiceTest {
    
        private static final String SOME_DEALS = "{ \"activeDeals\" : [ "
                +dealJson(new String[]{"1-2-3-4-5"}, "IT")+", "
                +dealJson(new String[]{"1-2-3-4-5"}, "DE")+", "
                +dealJson(new String[]{"5-5-5-5-5"}, "IT")+", "
                +dealJson(new String[]{"5-5-5-5-5"}, "FR")+", "
                +dealJson(new String[]{"3-3-3-3-3"}, "US")
                +"] }";
    
        private static final UUID uuid1_2_3_4_5 = UUID.fromString("1-2-3-4-5");
        private static final UUID uuid5_5_5_5_5 = UUID.fromString("5-5-5-5-5");
        private static final UUID uuid3_3_3_3_3 = UUID.fromString("3-3-3-3-3");
    
        private Request request;
        private Response response;
    
    
        /**
         * Json representation of a list of deals associated to a country
         */
        private static String dealJson(String[] uuids, String country) {
            // Not very interesting
        }
    
        /**
         * Inject in CatalogService a BlacklistProvider blacklisting the given set of deals
         */
        private static BlacklistProvider blacklist(Set<UUID> dealsToBlacklist) throws HttpReturnErrorException, IOException, InvalidAnswerException {
            BlacklistProvider blacklistProvider = createMock(BlacklistProvider.class);
            expect(blacklistProvider.getBlacklistedDeals()).andReturn(dealsToBlacklist);
            // here we have decided to inject a value in our CatalogService
            CatalogService.overrideBlacklistProvider(blacklistProvider);
            return blacklistProvider;
        }
    
        @Before
        public void setup() throws UnsupportedEncodingException, IllegalAccessException {
            // declare which static methods are we going to mock
            PowerMock.mockStaticPartial(URLEncoder.class, "encode");
            PowerMock.mockStaticPartial(CatalogService.class, "createGetRequest");
            PowerMock.mockStaticPartial(ServiceClient.class, "fire");
    
            // mocking request
            request = createMock(Request.class);
            expect(request.getURI()).andReturn("foo_uri").anyTimes();
    
            // mocking response
            response = createMock(Response.class);
            expect(response.formatStatusMessage()).andReturn("Everything is foo-k");
            expect(response.isSuccess()).andReturn(true).anyTimes();
            expect(response.getContent()).andReturn(SOME_DEALS).anyTimes();
    
            // mock a bit of other secondary methods
            expect(URLEncoder.encode(anyObject(String.class))).andReturn("FOO").anyTimes();
            expect(ServiceClient.fire(anyObject(Request.class), anyObject(HttpClient.class))).andReturn(response);
            expect(CatalogService.createGetRequest(anyObject(String.class), anyObject(String.class))).andReturn(request);
    
            // mocking logger
            Logger logger = new DummyLogger();
            Field field = PowerMock.field(CatalogService.class, "logger");
            field.set(CatalogService.class, logger);
        }
    
        /**
         * We invoke the method dealsToDisplay through reflection because it is private. 
         */
        private Map<UUID, Set<String>> invokeDealsToDisplay() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            Method method = CatalogService.class.getDeclaredMethod("dealsToDisplay");
            boolean accessibility = method.isAccessible();
            if (!accessibility) {
                method.setAccessible(true);
            }
            try {
                return (Map<UUID, Set<String>>)method.invoke(null);
            } finally {
                if (!accessibility) {
                    method.setAccessible(false);
                }
            }
        }
    
        @Test
        public void dealsToDisplayNoBlacklistingTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, IOException, HttpReturnErrorException, InvalidAnswerException {
            // No deals blacklisted
            BlacklistProvider blacklistProvider = blacklist(Collections.<UUID>emptySet());
    
            // ready to invoke the method under test
            PowerMock.replayAll(request, response, blacklistProvider);
    
            // We have to test this static private method in code considered legacy:
            // this is not going to be pretty...
            Map<UUID, Set<String>> result = invokeDealsToDisplay();
            assertEquals(3, result.size());
            assertTrue(result.containsKey(uuid1_2_3_4_5));
            assertTrue(result.containsKey(uuid3_3_3_3_3));
            assertTrue(result.containsKey(uuid5_5_5_5_5));
            assertEquals(Sets.newHashSet("IT", "DE"), result.get(uuid1_2_3_4_5));
            assertEquals(Sets.newHashSet("US"), result.get(uuid3_3_3_3_3));
            assertEquals(Sets.newHashSet("IT", "FR"), result.get(uuid5_5_5_5_5));
        }
    
        @Test
        public void dealsToDisplaySomeBlacklistingTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, IOException, HttpReturnErrorException, InvalidAnswerException {
            // Some deals blacklisted
            BlacklistProvider blacklistProvider = blacklist(Sets.newHashSet(uuid1_2_3_4_5));
    
            // ready to invoke the method under test
            PowerMock.replayAll(request, response, blacklistProvider);
    
            // We have to test this static private method in code considered legacy:
            // this is not going to be pretty...
            Map<UUID, Set<String>> result = invokeDealsToDisplay();
            assertEquals(2, result.size());
            assertFalse(result.containsKey(uuid1_2_3_4_5));
            assertTrue(result.containsKey(uuid3_3_3_3_3));
            assertTrue(result.containsKey(uuid5_5_5_5_5));
        }
    
        @Test
        public void dealsToDisplayCompleteBlacklistingTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, IOException, HttpReturnErrorException, InvalidAnswerException {// declare which static methods are we going to mock
            // All deals blacklisted
            BlacklistProvider blacklistProvider = blacklist(Sets.newHashSet(uuid1_2_3_4_5, uuid3_3_3_3_3, uuid5_5_5_5_5));
    
            // ready to invoke the method under test
            PowerMock.replayAll(request, response, blacklistProvider);
    
            // We have to test this static private method in code considered legacy:
            // this is not going to be pretty...
            Map<UUID, Set<String>> result = invokeDealsToDisplay();
            assertEquals(0, result.size());
            assertFalse(result.containsKey(uuid1_2_3_4_5));
            assertFalse(result.containsKey(uuid3_3_3_3_3));
            assertFalse(result.containsKey(uuid5_5_5_5_5));
        }
    
        private static class DummyLogger extends Logger {
            protected DummyLogger() {
                super("DummyLogger");
            }
    
            @Override
            public void error(Object message, Throwable t) {
                System.err.println("ERROR: " message " , " t.getClass());
            }
    
            @Override
            public void error(Object message) {
                System.err.println("ERROR: "+message);
            }
    
            @Override
            public void info(Object message) {
                System.err.println("INFO: "+message);
            }
        }
     }

Mocking Static Methods

In my scenario I had to:

  • invoke a private static method
  • mock several static methods

The former is easy, you just have to use reflection:

            Method method = CatalogService.class.getDeclaredMethod("dealsToDisplay");
            boolean accessibility = method.isAccessible();
            if (!accessibility) {
                method.setAccessible(true);
            }
            try {
                return (Map<UUID, Set<String>>)method.invoke(null);
            } finally {
                if (!accessibility) {
                    method.setAccessible(false);
                }
            }

We start by finding the method and we set is accessible (setting back the previous value when we are done). At this point we can invoke it. Nice. Sort of.

To mock static methods we have instead to use PowerMock which does the trick by using a custom Classloader and doing bytecode rewriting on the fly. Yes, it does not sound safe. No, there are no alternatives that I am aware of.

So we need to do a few things, first of all we have to instruct PowerMock to take care of loading the class through its Classloader:

@RunWith(PowerMockRunner.class)
@PrepareForTest( { CatalogService.class, Logger.class, URLEncoder.class, ServiceClient.class})
public class CatalogServiceTest {

Then we have to declare which methods we intend to mock:

// declare which static methods are we going to mock
PowerMock.mockStaticPartial(URLEncoder.class, "encode");
PowerMock.mockStaticPartial(CatalogService.class, "createGetRequest");
PowerMock.mockStaticPartial(ServiceClient.class, "fire");

Finally we mock them, specifying what result do we want when they are invoked:

expect(URLEncoder.encode(anyObject(String.class))).andReturn("FOO").anyTimes();
expect(ServiceClient.fire(anyObject(Request.class), anyObject(HttpClient.class))).andReturn(response);
expect(CatalogService.createGetRequest(anyObject(String.class), anyObject(String.class))).andReturn(request);

Conclusions

Our solution required a considerable amount of plumbing and mocking, mocking and plumbing, to test a very limited functionality. While we are happy with the result, and have reasonable confidence that this not destroy that old piece of code, it is clear that it is not an ideal scenario. But sometimes you have to do what you gotta do.

Bonus: Mocking Singletons

A common issue is the necessity of mocking singletons. While you can write your own recipe reusing the code presented in this post, you can also take a look at this post:

Mocking a singleton with EasyMock and PowerMock

Happy mocking!