Saturday 23 July 2011

Mock or Stub.. Test it inside out!!

If you have been living in the Test Driven Development (TDD) world, then Mocks and Stubs will be second nature to you. The very philosophy of writing a test case before writing any code sounds like putting the cart before the horse but when you start implementing the practice, it all begins to make sense. Your tests before 'smaller'. They don't have dependencies between them and your code is  much more readable and easier to maintain.

Mocking and Stubbing are two essential components of TDD. While they may appear to perform the same function, they are different sides of the coin. To understand the similarities and the differences between these two forms, consider for example, the class, Compute defined as follows:

public class Compute {
private Integer a;
private Integer b;
public Integer getA() {
if (a instanceof Integer)
{
return a;
}
return null;
}

public Integer getB() {
if (b instanceof Integer)
{
return b;
}
return null;
}

public Compute(Database db) {
this.a = db.getA();
this.b = db.getB();
}

public Integer addNumbers()
{
if  ((getA() != null) && (getB() !=null ))
{
return getA() + getB();
}
return null;
}

public static void main(String[] args) 
{
Compute comp;
Database db = new Database();
comp = new Compute(db);
comp.addNumbers();

}

}

In this example, Compute is getting its input from another class, Database. In the real world, Database would be actually be an RDBMS such as Oracle or MySQL. Since running test cases against a LIVE database can bring in additional complexity such as the setting up of a connection, running an SQL statement against the tables and retrieving the data, Mocking and Stubbing allows the role of the Database to be mimicked.

While there are several subtle differences, the major difference between the frameworks is that Mocks enable the testing of the behaviour of the code while Stubs allow the final result  to be tested.

To test the add Compute with the EasyMock framework, I would 'mock' the behaviour of the Database class using the EasyMock framework as follows:

 Compute compute;
Database mockDB;

@Before
public void setUp() throws Exception {

mockDB = EasyMock.createMock(Database.class);
EasyMock.expect(mockDB.getA()).andReturn(100);
EasyMock.expect(mockDB.getB()).andReturn(200);
EasyMock.replay(mockDB);
}

@After
public void tearDown() throws Exception {
mockDB = null;
compute = null;
}

@Test
public void testAddNumbers() {
compute = new Compute(mockDB);
assertEquals(300,compute.addNumbers(), 0);
}

In the  EasyMock, approach outlined above, we set up the expectations related to how the method calls related to retrieving and adding two numbers would play out and then Assert the actual result against the expected. To understand the code, check out this excellent summarisation of EasyMock. The main rule of thumb while writing a Mock is to specify exactly what should happen and no more

Using Stub frameworks, such as StubOuts to test the above scenario would require creating a Class that implements the addNumber and subtractNumber methods of the Compute class and returns hard coded values, to suit the test. For example, the testAddNumbers  method would look like this:
        
public Integer addNumbers()
{
if ((getA() == 100)  && (getB() ==200 ))
{
return 300;
}
  else
  {
return null;
  }
}

Mocks and Stubs are both powerful ways of testing code and catching regression.However both frameworks are applied differently and are suitable in different scenarios. To ensure a robust testing framework, both approaches should be used in conjunction.

No comments: