Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

How to mock up your Unit Test environment

I’ve been spending a lot of time lately thinking about unit tests – mainly why more developers aren’t using them. In my last article on this topic, we went over code coverage and some advanced JUnit techniques for writing less code in unit tests. This is all fine when you start writing a new application and everything is clean and pristine.

But sometimes you inherit a bunch of spaghetti code sitting inside a big legacy enterprise application, and everything you need to deal with is already there (and hopefully working properly). If you change something, how can you tell what will be affected? The side effects of your changes should be clear from the beginning. If only you could do unit tests AND see the ripple effect across the code too…

Well, you can. It’s called mocking, and it lets you create alternative realities for your application to play through, without having any side effects or consequences in reality.

In this post, I explain how to test the side-effects of the code, how to mock Java objects in tests, use mocks in JUnit, and isolate your JUnit tests from the other components in your system. If you’re new to JUnit, here’s a useful cheat sheet about JUnit 5 annotations and how to use them.

Testing the side effects of what you change

Let’s meet Matt. Matt is a software developer who just started working on a gigantic CRM application. His first task is to create a new business rule regarding the mailing of invoices. Some customers get invoices by email, but others want a physically printed copy of the invoice instead. In addition to the last article, Matt has read the first part of these posts and decided he wants to write unit tests for his code. One of the classes he has added is the following:

public class FinalInvoiceStep {
  private PrinterService printerService = null;
  private EmailService emailService = null;
  
  public FinalInvoiceStep(PrinterService printerService, EmailService emailService) {
    this.printerService = printerService;
    this.emailService = emailService;
  }

  public void handleInvoice(Invoice invoice, Customer customer) {
    if(customer.prefersEmails()) {
      emailService.sendInvoice(invoice,customer.getEmail());
    } else {
      printerService.printInvoice(invoice);
    }
  }
}

Looking below, we can see here the respective unit test:

public class FinalInvoiceStepTest {
  private FinalInvoiceStep finalInvoiceStep = null;
  private Customer customer = null;
  private Invoice invoice = null;
  
  @Before
  public void beforeEachTest() {
    customer = new Customer();
    finalInvoiceStep = new FinalInvoiceStep(Env.PrinterServiceLocator(),     Env.EmailServiceLocator());
    invoice = new Invoice();
  }

  @Test
  public void normalCustomer() {
    customer.wantsEmail(true);
    finalInvoiceStep.handleInvoice(invoice, customer);
  }

  @Test
  public void customerWithPrintedInvoice() {
    customer.wantsEmail(false);
    finalInvoiceStep.handleInvoice(invoice, customer);
  }
}

Matt runs the test and while everything passes he realises a few things:

  • An email has reached the test inbox he has created for the imaginary user (not so bad)
  • A test invoice has been printed to the company printer (very bad!)
  • He forgot to add any ASSERT code at the end of the tests (DUDE!!!)

How to manually mock up Java Objects

Let me start by saying that I DON’T RECOMMEND DOING THIS! But reading this section will help you understand Java mocks work under the good, and better realize how to mock JUnit tests.

Even if Matt’s organization has a staging environment with another printer, it is not realistic to actually print physical invoices every time this unit test runs. Matt also understands that this code in not a valid unit test since no assert methods are present. After some careful thinking he decides to write a new class used only for tests like this:

public class DummyPrinterService  implements PrinterService{
  boolean anInvoiceWasPrinted = false;
  @Override
  public boolean isPrinterConfigured() {
    return true;
  }
  @Override
  public void printInvoice(Invoice invoice) {
    anInvoiceWasPrinted = true;
  }
  public boolean anInvoiceWasPrinted() {
    return anInvoiceWasPrinted;
  }
}

This is a new class just for testing that is emulating a fake printer service. It doesn’t print anything, it just records that a print request arrived. There is also an additional method that checks if an invoice was “printed” or not. With that class in place, he rewrites the unit test as:

public class FinalInvoiceStepTestImproved {

private FinalInvoiceStep finalInvoiceStep = null;
private Customer customer = null;
private Invoice invoice = null;
private DummyPrinterService dummyPrinterService = null;

@Before
public void beforeEachTest() {
  dummyPrinterService = new DummyPrinterService();
  customer = new Customer();
  finalInvoiceStep = new FinalInvoiceStep(dummyPrinterService, Env.EmailServiceLocator());
  invoice = new Invoice();
}

@Test
public void normalCustomer() {
  customer.wantsEmail(true);
  finalInvoiceStep.handleInvoice(invoice, customer);
  assertFalse("Nothing should be printed",dummyPrinterService.anInvoiceWasPrinted());
}

@Test
public void customerWithPrintedInvoice() {
  customer.wantsEmail(false);
  finalInvoiceStep.handleInvoice(invoice, customer);
  assertTrue("Invoice was printed",dummyPrinterService.anInvoiceWasPrinted());
}
}

Thus the tests pass, and the assert methods work correctly. However, after some time Matt realizes that his solution does not really scale well.

He also has to write a dummyEmailService. He actually needs to write a lot of classes like this during development. The code grows and he also has to keep track of all these dummy classes, since when the “real” classes change, all these dummy classes need updating too. Soon his needs for verifying results become more demanding and his dummy classes also contain code on the order of methods that were called and complex initializer methods.

In the example above, Matt was testing a method that had only arguments and no return value. There are also cases however where Matt had to test methods that returned complex business objects, further complicating the code of the “fake” classes.

After a while Matt starts fantasizing that he could have a magic wand to use to instantly:

  • Create fake objects from real classes/interfaces
  • Instrument the fake objects to respond with specific data for each method
  • Verify the execution of methods in those fake objects
  • Verify the arguments passed in the methods of those fake objects
  • Throw optional Exceptions for some calls

This magic wand would make his life much easier! Well, Matt is lucky because this magic wand exists and its called Mockito (one of several frameworks designed for this purpose–note: magic wand not included.

The Recommended Way: Use a Mocking Framework

At RebelLabs, we sometimes say that smart + lazy = efficient. So why create a bunch of human error prone manual tests on-the-fly when you could be so much lazier and use a mocking framework, such as Mockito, EasyMock, JMockit or any other.

Mocking attempts to solve in an easy way the creation of fake objects that help the unit testing process. Mock objects sometimes remind me of the film “The Truman Show.” You use mocking in order to “fool” a Java object to think that it communicates with other real objects.

From the point of view of the tested class, the FinalInvoiceStep of the example, everything runs normally. It communicates with other objects and gets all the appropriate responses. Behind the scenes, however, this is only theater, a mummer’s show if you will, which has been carefully planned by you.

The mock objects within your library allow you to setup a controlled environment with strictly-defined deterministic behaviours by all objects involved with the class in question. I’ve added a visual here as an overview of mocking:

In your new theater, you should use a mocking framework to set the stage, in which you carefully monitor all interactions of the tested class in order to verify its effectiveness. Then you can see if all your “actors” performing properly.

So when should you use mocking?

I suggest using mocking when the class you want to unit test communicates with other classes that have side effects which should only be called in the real production system. Some random examples of such side effects I thought of are:

  • Charging a credit card or bank account
  • Printing medical records, invoices, personal documents, etc
  • Sending an overdue bill notification to a client via email
  • Sending a request to an external system
  • Launching weapons into a neighboring enemy solar system
  • Flooding the reactor core
  • Shutting down life support

You can also use mocking in other cases as well. I tend to mock some classes that are very slow and based on a lot of dependencies not needed for the unit test. Mocking is also great when you want to emulate strange errors such as a full hard disk, network failure, wrong serialized version etc.



Mockito: my favorite mocking library

Out of all the mocking frameworks out there, it would seem that Mockito has become one of the most popular, and it is the one I use and prefer. It has a lot of capabilities that we will not cover in this post, as with JUnit in the previous posts, so I recommend that you spend some time to explore all it has to offer.

In the case of Matt, there is no need for special dummy classes. Instead, Mockito can be used as follows:

public class FinalInvoiceStepTestMocked {
  private FinalInvoiceStep finalInvoiceStep = null;
  private Customer customer = null;
  private Invoice invoice = null;
  private PrinterService printerService = null;
  private EmailService emailService =null;

@Before
public void beforeEachTest() {
  printerService = Mockito.mock(PrinterService.class);
  emailService = Mockito.mock(EmailService.class);
  customer = new Customer();
  finalInvoiceStep = new FinalInvoiceStep(printerService, emailService);
  invoice = new Invoice();
}

@Test
public void normalCustomer() {
  customer.wantsEmail(true);
  finalInvoiceStep.handleInvoice(invoice, customer);
  //Nothing should be printed
  Mockito.verifyZeroInteractions(printerService); 
  //Something must be emailed 
  Mockito.verify(emailService).sendInvoice(invoice, customer.getEmail());
}

@Test
public void customerWithPrintedInvoice() {
  customer.wantsEmail(false);
  finalInvoiceStep.handleInvoice(invoice, customer);
  //Nothing should be  emailed
  Mockito.verifyZeroInteractions(emailService); 
  //The invoice must be printed
  Mockito.verify(printerService).printInvoice(invoice); 
}
}

Both Email and Printer Services are mocked. The FinalInvoiceStep class is then created with these two as constructor arguments. As far it is concerned it communicates with two real classes.

But in reality, we know that mocking is controlling these classes and observes all their input/output. Instead of assert methods, we use Mockito verify statements. These check that the appropriate method was called or not.

Mockito has some good, example-oriented documentation that you can study. Be sure not miss Argument Matchers and Argument Catchers.

A small note on testable code

If you are a seasoned developer then you should have noticed that it was not very hard at all to inject our mocks into the test class, because FinalInvoiceStep was using constructor-based dependency injection. This is a very important point to consider when developing an application since all the dependencies of your class are clearly shown in constructors or methods.

There are times, however, when a class has hidden dependencies. These come in the form of Singletons, Static utility classes and objects found via Service Locators. These hidden dependencies make mock testing much more difficult.

While it is possible to mock static objects, we suggest you refactor your code first to make these hidden dependencies visible.

Note: The process of writing testable code is a huge topic on its own and will probably be covered in future posts.

When NOT to use mocking

Always remember that you should mock the objects that your classes come in contact with because you are interested in the class itself and nothing else. If you want to see the interaction of the whole module then you need integration tests.

Therefore you should not use mocking when you are interested in:

  • Data that comes from external resources or the DB
  • Transactions
  • The interaction of your application with your application server or environment
  • Testing multiple modules together as a single component

For all these cases you need integration tests, because we are now looking beyond the classes themselves. If you have several objects that work correctly isolated (because the unit tests pass), this does not mean that they will also work correctly when used together. This is where integration tests come in.

Closing remarks…

In this post, we introduced and discussed the concept of mocks as a way to trick your unit tests into believing that it is carrying out actual commands, yet this is just a simple theater play taking place in an alternate reality.

The example I provided hopefully showed where the side effects of a class must be emulated so that the test runs in an isolated environment, and I also recommend trying out mocking frameworks (again, my favorite is Mockito) and use them as an example to verify the actions of mock objects. Keep in mind; there are times when mocking should NOT be used, and we’ll cover that in more detail sometime later.

In my next post, we will finally talk about integration tests and when to use this type of testing as opposed to unit tests. I also hope to demonstrate how to include unit tests in your build process and how to organize your build jobs so that tests run in an optimal way.

So thanks for tuning in, and feel free to post comments below regarding your opinion on mocking in Java, or ping us on Twitter @zeroturnaround.

Editor’s note: this post was updated for accuracy and refreshed with more up-to-date links.


Read next:

  • Jorge

    Very good articles, not too short nor too big, and easy to follow. Congrats.

  • Cethos

    “An email has reached the test inbox he has created for the imaginary user (not so bad)
    A test invoice has been printed to the company printer (very bad!)
    He forgot to add any ASSERT code at the end of the tests (DUDE!!!)”

    OK, I love your blog. Good work.

  • Ahahahahahaha!

  • Mohamed BENMOHAMED

    Great article :)

  • Lars

    This article is helpful, but some of your code samples look like this:

    “One of the classes he has added is the following:

    4e13f1c36f74d668c3fc8bdff90b5923000”

    I assume some code is supposed to appear there, instead of a long hex string. Is this some sort of broken reference?

  • Lyubka Genova

    Great article – i don’t know which to put first – that it is well-explained or that i laughed out from my heart while reading it!