There are several popular mocking frameworks available in the Java market and Mockito is one of them. Unit testing with mocking frameworks has seemed to be very useful recently. Mockito, down the years, has evolved into a distinct and a significant mocking framework although at the beginning it started off from the EasyMock framework. The PowerMock is another extension of EasyMock that enhanced many of the powerful capabilities of both EasyMock and Mockito. In this article, we’ll focus on unit testing with a mocking framework in general and Mockito framework in particular.
What Is Mocking?
The word “Mocking” typically means imitating or mimicking the behaviour of a real object (either in contempt or to ridicule). This idea got its place in unit testing in the sense that here mock objects are created to mimic real objects in a controlled fashion. The mock objects are basically a simulated version of the original object that is programmatically created to verify the behaviour of another object. It is no surprise that object-oriented programming works as a relationship between objects. As the context widens, the individual unit as an object may have to be expanded into modules. Therefore, when we test a component we may actually test modules as an individual unit and their relationship. Therefore, the point is that an individual object rarely makes any sense in a program. Objects work in relation. Thus, nit-picking a unit for testing is as much necessary as testing their relationship. The object mocking is a technique to test units in isolation by simulating its dependent units.
That’s Fine, but Why Do We Need to Create Mock Objects, After All?
There may be several reasons; a few of the convincing scenarios may be as follows:
- It may happen that a component that one wants to test depends upon another unit which is not yet developed or functional. Therefore, although one component is fully functional, ready to be tested, yet it cannot be tested because its dependent component is not ready to take part in the relationship. In this situation, what we can do is create a mock object of the non-functional unit and test one that is ready.
- Sometimes, a functional component that is to be tested is dependent upon another component which deals with operations that are time consuming, such as dealing with a database connection or massive I/O operation. The first component can be tested quickly if this lagging component is simulated or, in other words, mocked just for the sake of testing.
- In some cases, there are infrastructural problems such as a server may not be ready for request response or too heavy and, say, we simply want to test the I/O operation of a Web form. In such a scenario, mocking a server object can be a good idea because we do not actually require wakinh up a monster (say, an application server) just for the sake of unit testing a component that has little to do with another component although they seem to be related.
Perhaps, this gives you an idea of why we actually create a mock object. It is not difficult to add a few more scenarios, as stated previously.
The Mockito Framework
Please note that Mockito is one of the many popular mocking frameworks that provides APIs for creating mocking objects. It has numerous other functionalities apart from mere mocking. In fact, the use of test spies over mocks makes it a distinct framework over its predecessors. The focus on test-spies makes the API much cleaner. The APIs are intuitive, with simple syntaxes and have almost a flat learning curve. Mockito is particularly good for complex scenarios.
For the purist, it is worth mentioning that this framework is more regarded as a test-spies framework unlike other mocking frameworks. It is true that there are subtle differences. It also true that there is a whole lot of vocabulary, such as Dummy, Fake, Stubs, Spies, and Mocks to point out the difference, sometimes, quite intimidating. Read Martin Fowler’s Mocks Aren’t Stubs. Here is an excerpt (in italics) of a section from that article.
- Dummy objects are passed around but never actually used. Usually, they are just used to fill parameter lists.
- Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in-memory database is a good example).
- Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test.
- Spies are stubs that also record some information based on how they were called. One form of this might be an e-mail service that records how many messages it was sent.
- Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
In short, whatever we may call it, the common factor is that the process of testing A requires a missing part B and it is crucial that the part B be there to test A. But, in reality, part B cannot be taken into account for one or more reason. So, what we do is create “test doubles” just to test A. Now, according to the process applied, it may be classified as dummy, fake, stub, spy, or mock.
A Quick Example
Here is a section of a code showing how a database connection may be tested with the help of the Mockito Framework. The code is simple and self-explanatory. Consult the Mockito API documentation for specific details on any method or annotation.
The class to be tested:
package org.mano.examples3; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseService { private static Connection con; public DatabaseService() throws ClassNotFoundException, SQLException { if (con.isClosed()) { Class.forName("com.mysql.jdbc.Driver"); con = DriverManager.getConnection("jdbc:mysql:" + "//localhost:3306/tempdb", "root", "password"); } } public int runQuery(String sql) throws ClassNotFoundException, SQLException { return con.createStatement().executeUpdate(sql); } }
Sample Test class:
package org.mano.examples3.test; import org.junit.Assert; import org.junit.Before; import org.mano.examples3.DatabaseService; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.sql.Connection; import java.sql.Statement; public class DatabaseServiceTest { @InjectMocks private DatabaseService service; @Mock private Connection conn; @Mock private Statement stmt; @Before public void initTest() { MockitoAnnotations.initMocks(this); } public void testConnection() throws Exception { Mockito.when(conn.createStatement()) .thenReturn(stmt); Mockito.when(conn.createStatement() .executeUpdate(Mockito.anyString())).thenReturn(1); int result = service.runQuery(""); Assert.assertEquals(result, 1); Mockito.verify(conn.createStatement(), Mockito.times(1)); } }
Another Quick Example
package org.mano.examples3; public class Contact { private long id; private String name; private String phone; public Contact() { super(); } public Contact(long id, String firstName, String phone) { super(); this.setId(id); this.setName(getName()); this.setPhone(phone); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public long getId() { return id; } public void setId(long id) { this.id = id; } } package org.mano.examples3; public class ContactDAO { public Contact find(long id){ throw new UnsupportedOperationException(); } } package org.mano.examples3; public class ContactService { private ContactDAO contactDAO; public ContactService(ContactDAO contactDAO){ this.contactDAO = contactDAO; } public Contact find(long id){ return contactDAO.find(id); } }
Sample Test Class
package org.mano.examples3.test; import org.junit.Assert; import org.junit.*; import org.mano.examples3.*; import org.mockito.*; import org.mockito.junit.*; public class ContactServiceTest { @Mock private ContactDAO contactDAO; @Rule public MockitoRule rule = MockitoJUnit.rule(); @Test public void testFind() { MockitoAnnotations.initMocks(this); ContactService contactService = new ContactService(contactDAO); contactService.find(1L); Mockito.verify(contactDAO).find(1L); } @Test public void initTest() { ContactService s = new ContactService(contactDAO); Mockito.when(contactDAO.find(1L)) .thenReturn(testContact()); Contact c = s.find(1L); Assert.assertEquals("AAA", c.getName()); Assert.assertEquals("9182736450", c.getPhone()); Mockito.verify(contactDAO).find(1L); } public Contact testContact() { Contact contact = new Contact(1L, "AAA", "9182736450"); return contact; } }
Conclusion
For all practical purposes, Mockito works in association with the JUnit framework. It is, however, more a question of convenience than necessity. Mockito Framework empowers simple unit testing to a much higher level. The introduction of test doubles and test spies are a welcome respite to many test developers. It is difficult to venture into the realm of interactive testing without the active help of a framework such as Mockito. At the end, frameworks are just tools, but the testers make a system flawless.