Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts

Sunday, 10 February 2013

Testing Private methods using Reflection

Without entering into a debate of why or why not private methods should be directly tested, here are the various steps involved in testing a private method using Java Reflection.

Scenario 1 : The private method has no input parameters, operates on a private variable and returns a value.

The class to be tested.

package com.john.exeriment;

/**
 * The class to be tested.
 *
 */
public class App
{
private String name= "John";
private int numCharactersInName = 0;
 
public int getNumCharactersInName() {
return numCharactersInName;
}
private int getSizeOfName()
{
numCharactersInName = name.length();
return numCharactersInName;
}
public static void main( String[] args )
 {
App app = new App();

System.out.println(" The size of the name is " + app.getSizeOfName());

   }
}
-------------
JUNIT Class

package com.john.exeriment;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * Unit test for simple App.
 */
public class AppTest extends TestCase
{
    /**
     * Create the test case
     *
     * @param testName name of the test case
     */
    public AppTest( String testName )
    {
        super( testName );
    }

    /**
     * @return the suite of tests being tested
     */
    public static Test suite()
    {
        return new TestSuite( AppTest.class );
    }

/**
* Test method operates on the private field using its default value
**/
public void testAppMethod() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchFieldException
    {
    App myApp = new App();
        Method m = myApp.getClass().getDeclaredMethod("getSizeOfName", null);
        m.setAccessible(true);
        Integer size = (Integer) m.invoke(myApp, null);

    assertTrue( "Size should be ", size == myApp.getNumCharactersInName());
    }

We assume the method getNumCharactersInName() has been tested.


/**
* Test case modifies the private field of the class using Reflections before testing the required private method.
**/
public void testAppField() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException
    {
    App anotherApp = new App();
    Field field = anotherApp.getClass().getDeclaredField("name");
    field.setAccessible(true);
    field.set(anotherApp, "Testing!!!");
   
    Method m = anotherApp.getClass().getDeclaredMethod("getSizeOfName", null);
         m.setAccessible(true);
         Integer size = (Integer) m.invoke(anotherApp, null);
   
    assertEquals( "Size should be", 10,  size, 0.000001 );
    }

}



Scenario 2 : The private method takes a String as an input parameter and does not return a value.

We add the following method to our class.


private void getSizeOfName(String name)
{
numCharactersInName = name.length();
}


And to test it, we have the following JUNIT test.

public void testAppMethodWithInputParam() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
    App myApp = new App();
   
    // The parameter type
    Class[] parameterTypes = new Class[1];
        parameterTypes[0] = String.class;
        
        // The parameter value
        Object[] parameters = new Object[1];
        parameters[0] = "Cricket";
        
        Method m = myApp.getClass().getDeclaredMethod("getSizeOfName", parameterTypes);
        m.setAccessible(true);
        m.invoke(myApp, parameters);

    assertEquals( "Size is greater than 0", 7, myApp.getNumCharactersInName());
  }


In the test, we set up a String variable which we initialise to the value Cricket, and test if the method initialises the numCharactersInField correctly to 7 characters.

Thus, testing private methods via Reflection is a straightforward process and should be used if there are key parts of the business logic embedded in private methods.

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.

Sunday, 14 December 2008

In-Container testing with JUnit

Given the usefulness and success of a Test Driven Development(TDD) approach for developing (Java based) web applications, it is imperative that a developer chooses a good testing framework for writing unit tests. One such popular open-source test case framework is JUnit.

With JUnit 4.x, developer's can annotations to develop unit test cases. Annotations simplify the construction of test cases to a great extent leaving the developer to focus on writing the essential pieces of the testing logic. In an earlier post that included some test cases, I used the annotation
@Test that took care of marking the method as a JUnit test case to be executed by the Test Runner. Thus, all that I needed to write was the assertion for testing the method. A short tutorial on learning the essential JUnit annotations is given here while a more detailed learner guide is available here and an excellent cheat sheat can be downloaded here.

While JUnit is basically a unit testing framework for stand alone Java applications, testing web applications is an entirely different cup of tea. Web applications run within an application server (such as JBOSS), while JUnit executes its test cases in a local JVM. Then how do you test thosein-containerMock Object based approach and the second is to use another testing framework that directly performs in-container testing.

For a Struts based web application, the MockObject approach can be implemented using StrutsTestCase class. Apart from the StrutsTestCase, there are several other available frameworks such as EasyMock that allow you to easily mock up objects. It should be noted that the Mock Object approach is not the same as in-container testing of components.

In-container testing can be carried out using one of the testing frameworks that extend JUnit and enable end-2-end testing of the web application. Cactus, HttpUnit and HtmlUnit are three such testing frameworks. It should be noted that Cactus and Http/HtmlUnit provide different facets to testing the server components. While Cactus focuses on testing server objects in the J2EE spec such as Servlets, EJBs and JSPs, Http/HtmlUnit frameworks emulate the browser behaviour. In other words these frameworks help you test the rendered view after an Http Request. The good news is that these frameworks can be integrated and working together can provide excellent test coverage.

For more reading on unit testing Struts based applications with these testing frameworks, check out this excellent book chapter.

Saturday, 6 September 2008

Test Driven Development and a Code Kata

(Please click on the images to get a more readable version).


This week I thought of trying out a CodeKata problem and choose Kata 4 . The kata requires you to read a data file, parse it , extract some values and print the difference between them. A simple exercise one would say.

To explain the problem in brief. A data file containing the results of the football league is provided. The requirement is to extract the name of the team with the lowest goal difference in For and Against goal values. I decided to make this problem a bit more exciting by not just coding along a 'happy path' but also looking out for scenarios where there might be no valid data rows or there might be two teams matching the lowest goal difference criteria.

Using a test driven approach, I hacked out a set of basic JUnit tests to parse a valid data row and extract the For and Against goal values. My data row looked somewhat like this.



and the tests to extract the values from this data row looked like this:

Now that I was getting the For and Against Goal values, all I needed was to calculate their difference and store the team name (& goal difference) in a 'results list'. The tests for doing this were accomplished as below:

As evident from the test, my 'controller' class has ONE main function which is updateLowestGoalDifferenceTeam(). This function performs the core business processing in terms of updating the list holding the lowest goal difference team names. This function is given as below.




The function gets the list holding the team name, extracts the goal difference values and compares the same against the goal difference value passed to it as a parameter in a HashMap. If the passed in value is lower, the existing team becomes a part of the list.



In all the Kata was a simple excercise but it was instructive in analysing the data structures that could be used and in studying the different approaches that could be taken to solve this problem. If you would like to compare your efforts with mine or wanted to know more about the solution, ping me for the complete code as an Eclipse project.