How to test private instance variables in Java

Why test private instance variables?

Need to test private instance variables in Java? Well, if you ask how to do that on a discussion forum you’ll probably get the response that you shouldn’t test anything private. Instead, call the public method that’s calling using the instance variable and make sure it works the way it should. If the public method tests correctly then the private variable must be working.

But what if you’re teaching coders, especially new coders? It’s a lot easier to test each small piece individually and let them know what needs fixing and not waiting until the end.

Fortunately, all it takes is a little bit of Reflection.

Testing Methods

In all of the test cases that I build I have the following two methods.

private <T> T getField( Object instance, String fieldName ) throws Exception {
    Field fld = instance.getClass().getDeclaredField( fieldName );
    fld.setAccessible( true );
    return (T) fld.get( instance );
}

private void setField( Object instance, String fieldName, Object value ) throws Exception {

    Field fld = instance.getClass().getDeclaredField( fieldName );
    fld.setAccessible( true );
    if ( value instanceof Integer ) {
        fld.setInt( instance, (int) value );
    }
    else {
        fld.set( instance, value );
    }

}

Getting and setting values

Now that you’ve got the methods, it’s just a matter of using them.

Let’s say that you’ve got a student that is writing a constructor that should set the someVar instance variable to 3.

@test ( timeout = 250 )
public void test() throws Exception {
    SomeClass c = new SomeClass();
    int expected = 3;
    int actual = getField( c, "someVar" );
    assertEquals( expected, actual ); 
}

This goes out and checks that someVar was set to the right value.

But what if we want to go the other way. Instead of testing that the value is set correctly, we want to check that getSomeVar returns the correct value. This time we need to set someVar and then check the method to make sure it returns the right value.

@test ( timeout = 250 )
public void test() throws Exception {
    SomeClass c = new SomeClass();
    setField( c, "someVar", 3 );
    int actual = c.getSomeVar();
    assertEquals( 3, actual ); 
}

What’s about super classes?

Well, this falls apart a bit if you’re needing to test parent classes. The methods above will only look in the actual class and not upstream to the parents. There’s a way to make that work, but let’s save that for another post.

[dwqa_post_comments]