Introduction
This artical will show some basic concepts of mocking framework, why we should use it and walkthrough a simple that applied Mockito in Java.
The concept of mocking
Outside of the world of software development, the term “mock
” means to imitate or to mimic. A “mock
” can therefore be thought of as a stand-in, an imposter or as most commonly referred to as it pertains to softwaredevelopment, a fake
.
Fakes are often used as stand-ins for dependencies of the class under test.
Terms & Definitions |
Dependency – A dependency is when one class in an application depends upon another in order to perform its intended function. Dependencies are often stored in instance variables inside of the dependent class. |
|
Class Under Test – When writing unit tests, the term “unit” generally refers to a single class and specifically the class against which the tests are written. The class under test is therefore the application class that is being tested. |
Why Mock?
When we learn to program, our objects are usually self contained. Any hello world has no dependencies on outside classes (System.out aside) and neither do many of the other classes we write in the process of learning a language. However, in the real world, software has dependencies. We have action classes that depend on services and services that depend on data access objects (DAOs) and the list goes on.
The idea of unit testing is that we want to test our code without testing the dependencies. This test allows you to verify that the code being tested works, regardless of it's dependencies. The theory is that if the code I write works as designed and my dependencies work as designed, then they should work together as designed. The code below would be an example of this:
import java.util.ArrayList;
public class Counter {
public Counter() {
}
public int count(ArrayList items) {
int results = 0;
for(Object curItem : items) {
results ++;
}
return results;
}
}
I know the above example is about as simple as you get, but it illustrates the point. If you wanted to test the method count, you would write at test that addressed how the count method works. You aren't trying to test that ArrayList works because you assume that it has been tested and works as designed. Your only goal is to test your use of ArrayList.
The concept behind mock objects is that we want to create an object that will take the place of the real object. This mock object will expect a certain method to be called with certain parameters and when that happens, it will return an expected result.
What are the key mocking concepts?
When it comes to mocking, there are only 3 things you really need to worry about; stubbing, setting expectations and verifying. Some unit test scenarios don’t involve any of these, others involve only stubbing and others involve setting expectations and verifying.
Stubbing
Stubbing is the process of telling your fake how to behave when it is interacted with. You can generally stub public properties (those with getters and/or setters) and public functions.
When it comes to stubbing functions, you have a lot of choices typically. You may wish to return a specific value, throw an error or dispatch an event. Further, you may wish to indicate that the function behave differently depending upon how it is invoked (i.e. by matching the types or values of the parameters passed to the function).
If this sounds like a lot of work, it can be, but it generally isn’t. One great feature of many of the mocking frameworks is that you need not stub void functions. Nor do you have to stub any functions that are not invoked or properties that are not consulted during the execution of your tests.
Setting expectations
One of the key features of a fake is the ability to tell the fake what you expect when your test runs. For example, you may expect that a specific function be invoked exactly 3 times. You may expect that it never be invoked. You may expect that it be invoked at least twice, but not more than 5 times. You may expect that it be invoked with specific types of arguments or specific values or any combination of the above. The possibilities are endless.
Setting expectations is the process of telling your fake what you expect to happen to it. Remember that since it’s a fake, nothing actually happens. But, your class under test is none the wiser. From its perspective, it invoked the function and expects that it did whatever it was supposed to do.
For what it’s worth, most mocking frameworks let you create mocks of interfaces or public classes. You are not limited to having to mock only interfaces.
Verifying
Setting expectations and verification go hand in hand. Setting expectations is done prior to invoking the function(s) on the class under test. Verification is done after. So, first you set expectations, then you verify that your expectations were met.
From a unit testing perspective, if your expectations were not met, the unit test fails. For example, if you set the expectation that the ILoginService.login function should be invoked exactly once with a specific username and password, but it was never invoked during the execution of your test, then the fake would not verify and the test should fail.
What are the benefits of mocking?
You can create tests in advance; TDD
This one is one of the stronger benefits. If you create a Mock you can write Service Tests before the service is created, giving you the ability to add the tests to your automation environment in the development process. In other words, Service Mocking gives you the ability to use Test Driven Development.
Teams can work in parallel
This is similar to the above; create tests for code that does not exist. But the previous point was for the developer who writes tests, this one is for the Testing Team. How does the team start creating tests when you don’t have anything to test? Mock it and write tests against the Mock! This means it’s actually possible for the QA Team to have a full suite of tests ready when a service is ready to be tested; we don’t have downtimes when one team waits for the other to finish. This makes the financial argument for mocking particularly strong.
You can create proof of concepts or demos.
Since Mocks can (done levelheadedly) be very cost efficient to make, Mocks can be used to create a proof of concept, as a wireframe, or as a demo for something you’re considering building. This is very powerful and gives a good ground for making decisions about both whether to go ahead with a development project or not, but most importantly for actual design decisions.
You can write test for resource not accessible
This is one of those benefits that doesn’t fall into the actual benefits category, but rather works as a life saver. Ever wanted to test or use a service, only to get told that the service is behind a firewall and that that firewall can’t be opened for you or that you’re an authorized to use it? When you do, a MockService placed in an accessible place, including on your local computer, is a life saver.
Mock can be delivered to the customer
There are cases where there are reasons why you can’t allow access to your test systems for external sources, like partners or customers. These reasons can be access security, sensitivity of information, or just the fact that the test environment might not be accessible 24/7. In these cases; how do you provide a test system for your partner or customer to start development or test against? An easy solution is to provide a mock, either from your network or from your customers own network. A soapUI mock is extremely easy to deploy, it can either run in soapUI or exported as a .WAR file and placed in your java server of choice.
You can isolate systems
Sometimes you would like to test a part of your system without having other system parts affect it. This because the other systems will add noise to the test data and make it harder to make good conclusions from the data collected. Using mocks you can remove all dependencies mocking all systems except the one system you need to pinpoint in your tests. When doing mocks for isolation these mocks can be made extremely simple but reliable, fast, and predictable. This gives you a test environment where you have removed all stochastic behavior, have repeatable patterns and can monitor specific systems well.
Mockito framework
Mockito is an open source testing framework for Java released under the MIT License.
Mockito distinguishes itself from other mocking frameworks by allowing developers to verify the behavior of the system under test (SUT) without establishing expectations beforehand.[4] One of the criticisms of mock objects is that there is a tighter coupling of the test code to the system under test.[5] Since Mockito attempts to eliminate the expect-run-verify pattern[6] by removing the specification of expectations, the coupling is reduced or minimized. The result of this distinguishing feature is simpler test code that should be easier to read and modify.
You can verify interactions:
List mockedList = mock(List.class);
<span class="Apple-tab-span" style="white-space: pre;">
</span>
mockedList.add("one");
mockedList.clear();
verify(mockedList).add("one");
verify(mockedList).clear();
Or stub method calls
LinkedList mockedList = mock(LinkedList.class);
<span class="Apple-tab-span" style="white-space: pre;">
</span>
when(mockedList.get(0)).thenReturn("first");
<span class="Apple-tab-span" style="white-space: pre;">
</span>
System.out.println(mockedList.get(0));
<span class="Apple-tab-span" style="white-space: pre;">
</span>
System.out.println(mockedList.get(999));
A simple example Java code used Mockito
Without Mock framework
With Mockito framework
Step 1: Create a Maven project in Eclipse
Define the pom.xml
as below :
="1.0"="UTF-8"
<pre><project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>vn.com.phatbeo.ut.mockito.demo</groupId>
<artifactId>demoMockito</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demoMockito</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Step 2: Add java source code
Class Person.java
package vn.com.enclave.phatbeo.ut.mockito.demo;
public class Person
{
private final Integer personID;
private final String personName;
public Person( Integer personID, String personName )
{
this.personID = personID;
this.personName = personName;
}
public Integer getPersonID()
{
return personID;
}
public String getPersonName()
{
return personName;
}
}
Interface PersonDAO.java
package vn.com.enclave.phatbeo.ut.mockito.demo;
public interface PersonDao
{
public Person fetchPerson( Integer personID );
public void update( Person person );
}
Class PersonService.java
package vn.com.enclave.phatbeo.ut.mockito.demo;
public class PersonService
{
private final PersonDao personDao;
public PersonService( PersonDao personDao )
{
this.personDao = personDao;
}
public boolean update( Integer personId, String name )
{
Person person = personDao.fetchPerson( personId );
if( person != null )
{
Person updatedPerson = new Person( person.getPersonID(), name );
personDao.update( updatedPerson );
return true;
}
else
{
return false;
}
}
}
Step 3: Added unit-test class.
Then, jump to write unit test cases for class PersonService.java
In assumption, class PersionServiceTest.java
is as below:
package vn.com.enclave.phatbeo.ut.mockito.demo.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class PersonServiceTest
{
@Mock
private PersonDao personDAO;
private PersonService personService;
@Before
public void setUp()
throws Exception
{
MockitoAnnotations.initMocks( this );
personService = new PersonService( personDAO );
}
@Test
public void shouldUpdatePersonName()
{
Person person = new Person( 1, "Phillip" );
when( personDAO.fetchPerson( 1 ) ).thenReturn( person );
boolean updated = personService.update( 1, "David" );
assertTrue( updated );
verify( personDAO ).fetchPerson( 1 );
ArgumentCaptor<Person> personCaptor = ArgumentCaptor.forClass( Person.class );
verify( personDAO ).update( personCaptor.capture() );
Person updatedPerson = personCaptor.getValue();
assertEquals( "David", updatedPerson.getPersonName() );
verifyNoMoreInteractions( personDAO );
}
@Test
public void shouldNotUpdateIfPersonNotFound()
{
when( personDAO.fetchPerson( 1 ) ).thenReturn( null );
boolean updated = personService.update( 1, "David" );
assertFalse( updated );
verify( personDAO ).fetchPerson( 1 );
verifyZeroInteractions( personDAO );
verifyNoMoreInteractions( personDAO );
}
}
Points of Interest
+ What's Mock framework in overview.
+ Why we use Mockito in testing in Java development.
References
http://java.dzone.com/articles/the-concept-mocking
http://en.wikipedia.org/wiki/Mockito
http://code.google.com/p/mockito/
History
First release on Dec 26, 2012