Unit Testing with Mocks
I don’t find a convincing reason for switching to mocking frameworks from hand written stubs explained in previous sections. Nor do we need other frameworks in the market, but using mocking frameworks makes lives of an application developer much easier and simpler to some extend for sure.
Few points which come to mind in this regard, mainly the fact that after a while your tests become incomprehensible with your hand written test stubs. In other words, you write code to stub, or return values depending on what happens which takes both time and effort. A mocking framework can do all this in a matter of lines. The benefits of a mocking framework are:
- Easier (yes it is subjective)
- Less Code
- Follows DRY (Don’t Repeat Yourself)
According to Martin Fowler’s article “Mocks Aren’t Stubs” (http://martinfowler.com/articles/mocksArentStubs.html), the basic difference between mock and stub can be summarized as:
- A stub’s job is to return known results to all calls send to it.
- A mock additionally expects calls to come in a specific order, with specific parameters, and will throw an exception when these expectations are not met.
There are some error conditions that cannot be tested using stubs. On the other hand, tests using mocks are often much less stable. While stubs can be written manually with reasonable effort, mocks would require far more work. In addition, a good mocking framework can make writing stubs faster and easier as well.
There are various steps in executing a test using mocks. They are:
- Using a mock library, generate a mock object.
- According to the scenario required for testing, record a mock with the expectation needed. Identify the methods to be called and the values to be return in this step.
- Execute the scenario.
- Verify that the mock expectations are met.
Martin Fowler
He is an author, speaker, and loud-mouth on the design of enterprise software. He works for ThoughtWorks, a software delivery and consulting company. He popularized the term Dependency Injection (DI) as a form of Inversion of Control (IoC).
Mock Libraries
Libraries that give us an easy way to create mocks are called mock libraries/frameworks. Different frameworks provide their own ways to define the expectations and a variety of features to check the tested object’s behavior. Some of the well-known frameworks are listed below. These need not be the best in the industry nor the does the order reflect any implied priority of importance. Among the available mock frameworks, I will be giving an overview of the following in some detail.
- EasyMock
- jMock
- Mockito
Apart from the above mock frameworks, there are other frameworks like SevenMock, rMock, Unitils, Mochachino, PowerMock etc. available in the market which can also be used for doing unit testing using mocks in your application.
Mocking frameworks tend to become different according to the mocking approach they take. According to the approach they take they tend to have advantage and disadvantages. Generally we can classify any mocking frameworks into two categories based on this. They are:
- Proxy – Using the Java Reflection API to create the mock object
- Remapping Class – Using Java Instrumentation API to remap the class in the class loader
EasyMock
One of the very popular mocking frameworks available in the industry as of now. It is used extensively in the Spring framework for various testing requirements.
EasyMock provides three different ways to instantiate mock objects accordingly its behavior changes. They are:
- EasyMock.createMock() – doesn’t verify the order in which methods are called. When any exception happens, throws AssertionError.
- EasyMock.createStrictMock() – it verifies the order in which methods are called. In case of any errors during method execution throws AssertionError.
- EasyMock.createNiceMock() – doesn’t verify the order in which methods are called. In case of any errors during method execution return appropriate empty values.
The third option can be used for creating stubs but first and second option can only be used for creating pure mocks.
Listing 7-4. Example test class showing the usage of EasyMock to create mock objects for testing
[java]import static org.easymock.classextensions.EasyMock.*;
public class CustomerServiceTests{
private CustomerRepository customerRepository = createMock(CustomerRepository.class);
private CustomerService customerService = new CustomerServiceImpl(customerRepository);
@Test
public void customerExistsTest(String user){
expect(customerRepository.getCustomer(“john”)).andReturn(new Customer(“john”,”12345”));
replay(customerRepository);
boolean result = customerService.customerExists(“john”);
assertTrue(result);
verify(customerRepository);
}
}[/java]
In Listing 7-4, when expect method is called, the mock object is not created. It just records the expected method which has to be called. The actual mock object is created and loaded when replay method is called. When calling verify method it just makes sure that no method call has been omitted while executing this test case.
Various features of EasyMock can be summarized as follows:
- Can be used to mock interfaces, abstract classes and concrete classes.
- While mocking final classes, throws exception.
- When mocking final and static methods, it actually delegates the call to the actual implementations
- Mock objects created can be converted from one type to another (default, strict and nice)
jMock
jMock focuses on explicitly specifying behavior of the mocks using a specialized DSL (Domain Specific Language) embedded in the Java code. jMock instantiates both stub and mock objects in the same way. It can mock interfaces using an instance of the org.jmock.Mockery class. The test case class must be annotated with @RunWith(JMock.class) for JUnit4 which is shown in Listing 7-6 below.
Even though jMock is also a well-known framework, in my opinion it has cumbersome syntax and doesn’t provide any additional features to compete with the other mocking frameworks like EasyMock or Mockito.
Listing 7-5. Example test class showing the usage of jMock to create mock objects for testing
[java]import org.jmock.Mockery;
public class CustomerServiceTests{
Mockery context = new Mockery();
private CustomerRepository customerRepository = context.mock
(CustomerRepository.class);
private CustomerService customerService = new CustomerServiceImpl(customerRepository);
@Test
public void customerExistsTest(String user){
context.checking(new Expectations() {{
oneOf(customerRepository). getCustomer ("john");
will(returnValue(new Customer(“john”,”12345”)));
}});
customerService.customerExists(“john”);
}
}[/java]
Listing 7-6. @RunWith annotation used in case of JUnit4
[java]@RunWith(JMock.class)
public class ListTest {
Mockery context = new JUnit4Mockery();
@Test
public void doMockInterface() {
List mockList = context.mock(List.class);
}
@Test
public void doMockClass() {
ArrayList mockList = context.mock(ArrayList.class);
}
}[/java]
By default mocked objects are strict. However, it is possible to change this behavior by declaring expectations by using either ignoring or allowing as shown in Listing 7-7. These two approaches are one and the same and one can choose the method that best expresses the purpose you are looking for in your application.
Listing 7-7. Usage of ignoring and allowing in jMock
[java]context.checking(new Expectations() {
{
ignoring(mockOne);
allowing(mockTwo);
}
});[/java]
The various features of jMock library can be summarized as below:
- Mocked objects are strict by default
- Let’s you mock interfaces, abstract classes and concrete classes
- Throws exception when mocking final classes
- Similar to EasyMock, it delegates to actual implementation when mocking final and static methods
- Returns default values for mocked methods
- Makes it quick and easy to define mock objects.
- Let’s you precisely specify the interactions between your objects.
- Plugs into your favorite test framework.
- Easy to extend.
Mockito
Mockito does not make any difference between mock and stub objects. One can obtain a mock object using the Mockito.mock() method as shown in Listing 7-8.
To create a stub or a mock, use mock(class). Then use when(mock).thenReturn(value) to specify the stub value for a method. If you specify more than one value, they will be returned in sequence until the last one is used, after which point the last specified value gets returned.
Listing 7-8. Example test class showing the usage of Mockito to create mock objects for testing
[java]import static org.mockito.Mockito.*;
public class CustomerServiceTests{
private CustomerRepository customerRepository = mock(CustomerRepository.class);
private CustomerService customerService = new CustomerServiceImpl(customerRepository);
@Test
public void customerExistsTest(String user){
when(customerRepository.getCustomer(“john”)).thenReturn(new Customer(“john”,”12345”));
boolean result = customerService.customerExists(“john”);
assertTrue(result);
verify(customerRepository).getCustomer(“john”);
}
}[/java]
The various features of Mockito library can be summarized as below:
- Mocked objects are not strict by default
- With just an annotation you can mock objects
- Let’s you mock interfaces, abstract classes and concrete classes
- Throws exception when mocking final classes
- Similar to EasyMock and jMock, it delegates to actual implementation when mocking final and static methods
- Returns default values for mocked methods
- Allows to specify how many times you expect a certain method to be called
- With doAnswer() method you have provision of adding logic to your stubbed implementation
Page Visitors: 5830
Tomcy John
Latest posts by Tomcy John (see all)
- A Guide to Continuous Improvement for Architects - February 2, 2023
- Cloud-first Architecture Strategy - January 26, 2023
- Architecture Strategy and how to create One - January 24, 2023
I wanted to put you the little note to finally thank you over again with your wonderful knowledge you’ve documented on this page. This is really shockingly generous of people like you to deliver publicly all most people would’ve made available as an e book to earn some cash for their own end, primarily considering the fact that you might have tried it if you wanted. Those tips likewise acted like the fantastic way to be sure that someone else have similar zeal just as my own to realize many more in regard to this issue. I’m certain there are several more pleasurable sessions up front for people who see your blog.
Valuable information. Fortunate me I found your web site by accident, and I’m shocked why this coincidence didn’t took place earlier! I bookmarked it.
Hello There. I found your blog using msn. This is an extremely well written article. I will be sure to bookmark it and come back to read more of your useful info. Thanks for the post. I will certainly comeback.
As a Newbie, I am continuously browsing online for articles that can aid me. Thank you
I think this is a real great article post.Really looking forward to read more. Want more.
Thanks, nice post