Showing posts with label JUnit. Show all posts
Showing posts with label JUnit. 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.