有些私有方法有很明确的功能,算法比较复杂,不测可能会出问题。测的话最简单的方法是把测试用例写在类内部,例如下面的类:
package com.boco.godu.gapi;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class ConnManager {
private static String buildConnPoolID(int connType, String ip, int port, String loginArg1, String loginArg2) {
return connType + ip;
}
@Test
public void testPoolID() {
assertEquals("23ipstr", buildConnPoolID(23, "ipstr", 3, null, null));
}
}
但这样测会有几个问题:首先是如果测试方法很多,会把源代码文件搞得很臃肿,其次发布的时候需要将测试代码删除(毕竟不是产品的一部分),以后再需要测试的时候还得重写,最后这样的测试在BVT的时候无法运行,工作量也无法体现出来(BVT的测试用例都是写在单独的测试类中)。所以理想的方法是把测试方法写在单独的测试类中。
下面采用Java的反射机制实现这一目标。首先是被测类:
package org.leechau.testPrivateMethod;
public class ClassTested {
private String buffer ;
private String privateFoo (int a, String b) {
return a + b;
}
}
然后是测试类:
package org.leechau.testPrivateMethod;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.BeforeClass;
import org.junit.Test;
public class PrivateMethodTest {
private static ClassTested oClassTested;
private static Method newPrivateFoo;
private static Field buffer;
@BeforeClass
public static void buildDupObj() throws NoSuchMethodException {
// Get the class of the private method.
oClassTested = new ClassTested();
Class<?> cNewClassTested = oClassTested. getClass ();
// Change the property of the private method to be accessible.
newPrivateFoo = cNewClassTested. getDeclaredMethod ("privateFoo",
int.class, String.class);
newPrivateFoo. setAccessible (true);
buffer = cNewClassTested . getDeclaredField ("buffer");
buffer. setAccessible (true);
buffer. set ( oClassTested , "abcdefg");
}
@Test
public void privateFooTest() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
// Run the private method.
Object oActual = newPrivateFoo. invoke (oClassTested, new Integer(169), new String("_ABC"));
// Test the private method
String sActual = oActual.toString();
String sExpected = "169_ABC";
assertEquals(sActual, sExpected);
Object result = buffer. get ( oClassTested );
assertEquals("bcdefg", result);
}
@Test
public void privateFooTest2() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Object oActual = newPrivateFoo. invoke (oClassTested, new Integer(169), new String("_DEF"));
String sActual = oActual.toString();
String sExpected = "169_DEF";
assertEquals(sActual, sExpected);
}
}
这里要注意的是,JUnit 4里一个测试类执行顺序为:@BeforeClass –> @Before –> @Test –> @After –> @AfterClass,其中@BeforeClass和@AfterClass标记仅在测试类的初始化和清理时运行一次且必须是static方法,而@Before/@After标记是在每个@Test方法运行前/后都运行一遍,因此每一个测试方法的调用顺序为:@Before –> @Test –> @After。在JUnit 3里没有@BeforeClass和@AfterClass标记,起初始化和清理任务的方法必须命名为SetUp()和TearDown()。