Eleventy-two

Tag: testing

Unit testing private methods in Java.

by Mex on Mar.15, 2009, under Technology

Junit

Junit

Unit tests are both the saviour and ultimate bane of modern java programmers.  Very few people would argue that they are a bad idea, and that they improve the quality of code but for those new to writing unit tests are often lost on where to start. In this post I am going to talk about unit testing private methods, and what is good and bad about doing so.

Some Theory.

In the example below ClassWithPrivateMethod contains the private method someMethod which we want to test. To get access to this method for testing we could make it public/protected; but that would make the classes interface ugly, and give people access to functions that could break the working of the class. We could put the test case inside the class being tested, but this quickly becomes messy. Ideally we want the method to remain private but be accessed from another class. It turns out that private methods are not private, as much as books on Java will tell you they are. Using reflection it is possible to execute private methods as if they were public.

public class ClassWithPrivateMethod {
  private void someMethod(String param) {
    System.out.println(param + " World");
}
}

To call a method with reflection we first need a reference to the method. This is normaly done with Reflection.getMethod, however because the method we want to access is not public we have to use Reflection.getDeclaredMethod. This gives us a handle on the method, but it is unusable because the method is still private. Calling setAccessible(true) on this method object lets us invoke it. The method can now be called via reflection the same way a public method would be. Bellow is a clearer example of a test that simply invokes the private method.

public class Test {
	@Test
	public void test() {
		Method methodToTest =
			classWithPrivateMethod.getClass().
			getDeclaredMethod("someMethod", String.class);
		methodToTest.setAccessible(true);
		methodToTest.invoke(IntancetoInvokeOn, "hello");
	}
}

This technique can be further extrapolated to testing methods which rely one some state of the object which is difficult to achieve in a normal unit test.

public class ClassWithPrivateMethodandFields {
	private int x,y;
	private boolean isPair() {
		return x==y;
	}
}
public class Test {
	@Test
	public void test() {
		Method methodToTest =
			classWithPrivateMethod.getClass().
			getDeclaredMethod("someMethod", String.class);
		methodToTest.setAccessible(true);
 
		Field x = classWithPrivateMethod.getClass()
			.getDeclaredField("x");
		x.setAccessible(true);
 
		Field y = classWithPrivateMethod.getClass()
			.getDeclaredField("y");
		y.setAccessible(true);
 
		methodToTest.invoke(IntancetoInvokeOn, "hello");
	}
}

Finally

This is a powerful tool for testing, but over use can highlight the fact that your interface is not as clean as it could be. I hope this is helpful to people and if you have any ideas or comments please leave them below.

1 Comment :, , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...

Archives

All entries, chronologically...