Unit Testing internal object state

I don’t know what XPers whould say about this, but I found it useful. Maybe someone could say: if you are not able to test something of your API, maybe you’ve badly designed your components… or: you should’n test this, because this is internal specifics of your object and you don’t have to know or test it: if you change internal implementation your test will fail. or… you need this ‘xyz’ test pattern. or… I don’t know. This is why following code has been posted in my ‘horror code’ category.
Here’s the base class I used to implement some junit TestCases that need to access to internal details of my objects:

/**
 * $Id: InternalAccessorTestCase.java 77 2005-12-06 14:46:42Z luigi $
 */
package it.newinstance.test.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import junit.framework.TestCase;

/**
 * Base class for TestCases that need to access private fields and methods
 */
public abstract class InternalAccessorTestCase extends TestCase {

    protected static Object getFieldValue(Object o, String fieldName) {
        try {
            return getField(o.getClass(), fieldName).get(o);
        } catch (Exception x) {
            throw new RuntimeException(x);
        }
    }

    protected static Object invoke(Object o, String methodName, Object[] args,
            Class[] types) {
        try {
            return getMethod(o.getClass(), methodName, types).invoke(o, args);
        } catch (Exception x) {
            throw new RuntimeException(x);
        }
    }

    private static Field getField(Class clazz, String fieldName)
            throws NoSuchFieldException {
        try {
            Field f = clazz.getDeclaredField(fieldName);
            f.setAccessible(true);
            return f;
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            if (clazz == Object.class)
                throw e;
            return getField(clazz.getSuperclass(), fieldName);
        }
    }

    private static Method getMethod(Class clazz, String methodName,
            Class[] types) throws NoSuchMethodException {
        try {
            Method m = clazz.getDeclaredMethod(methodName, types);
            m.setAccessible(true);
            return m;
        } catch (SecurityException x) {
            throw new RuntimeException(x);
        } catch (NoSuchMethodException x) {
            if (clazz == Object.class)
                throw x;
            return getMethod(clazz.getSuperclass(), methodName, types);
        }
    }
} 

I needed to check the internal state of an object, that does some job, but does not expose anything that can be tested. I just parse some xml and instantiate an object with its components, then I needed to test that the composition has been done as I expect.
This is how my test appears:

/**
 * $Id: ParserTest.java 81 2005-12-06 23:08:42Z luigi $
 */
package it.newinstance.test.watchdog.xml;

import java.util.List;

public class ParserTest extends InternalAccessorTestCase {

    public void testServerWithOneMonitorAndOneListener() throws Exception {...}

    public void testServerWithMonitorWithParametersAndNullListener()
            throws Exception {
        String xmlPath = getCurrentPath()
                + "/ServerWithMonitorWithParametersAndNullListener.xml";
        Server s = new Parser(Util.getStream(xmlPath)).parse();
        assertNotNull(s);
        List monitorEntries = (List) getFieldValue(s, "monitorEntries");
        assertTrue(monitorEntries.size() == 1);
        for (Object monitorEntry : monitorEntries) {
            MockMonitorWithParameters m = (MockMonitorWithParameters)
                getFieldValue(monitorEntry, "monitor");
            assertEquals("thisIsATest", m.getStringValue());
            assertEquals(10, m.getIntValue());
            assertEquals(5.5, m.getDoubleValue(), 0.0D);
            assertEquals(true, m.isBooleanValueTrue());
            assertEquals(false, m.isBooleanValueFalse());
            assertEquals(new Integer(15), m.getWrapperIntegerValue());
            assertEquals(new Double(3.14D), m.getWrapperDoubleValue(), 0.0D);
            assertEquals(Boolean.TRUE, m.getWrapperBooleanValueTrue());
            assertEquals(Boolean.FALSE, m.getWrapperBooleanValueFalse());
            List listeners = (List) getFieldValue(m, "listeners");
            assertTrue(listeners.size() == 1);
            for (Object object : listeners) {
                Listener listener = (Listener) object;
                assertEquals("MyListenerName", listener.getName());
            }
        }
    }

    private String getCurrentPath() {
        return getClass().getPackage().getName().replace('.', '/');
    }
} 

Calls to getFieldValue utility methods, makes access to private member variable of object(s) to be tested. I made two methods: getFieldValue to access private field of objects, and invoke, that is able to invoke private methods of my test objects.

Maybe this code is horror enough (?): recently I am neglecting this blog, and also posting so few about code… I’m doing not much interresting coding, but I enjoy what I read on jroller and other blogs…


No Responses to “Unit Testing internal object state”  

  1. No Comments

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>



Calendar

December 2005
M T W T F S S
« Nov   Jan »
 1234
567891011
12131415161718
19202122232425
262728293031  

Follow me

twitter flickr LinkedIn feed

Subscribe by email

Enter your email address:

Archives


Categories

Tag Cloud


Listening