image resource how to mock up your unit test environment to create alternate realities
December 2, 2016

Mock Testing Java With Mockito

Java Testing
Enterprise Development

In this article I'll show you how to mock up test a Java environment manually using the mock framework, Mockito. I'll create a mock testing example and take you step by step through mocking in Java. You'll learn:

Back to top

Unit Test Limitations

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.

Mock Testing to the Rescue

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, mock up test 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.

Back to top

Mock Up Test Example

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.

Back to top

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 in unit testing 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 unit testing:

mock up test comparison

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” are performing properly.

So when should you use mocking? I suggest using mocking in unit testing 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.

Back to top

Mockito Mocking Framework

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.

Back to top

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 a Mock Up Test

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.

Final Thoughts

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.

Looking for additional tools to help your code perform its best? Try JRebel for free for 14 days and see how much time your team could save by eliminating redeploys. 

Start My Trial

Additional Resources

If you enjoyed this post, you may also be interested in this related content:

Related Content

Back to top