最近在对一个比较复杂的java后台程序进行单元测试,需要使用JUnit测试框架。但是由于后台业务太过复杂,甚至构造比较完整的测试数据都要花上一天的时间才能够搞定。一开始我采用最笨的方法,从最外部调用该API,需要一层一层的往下调用才能调到我需要测试的程序,这样的方法固然是可靠、可行的。但是,感觉这背离的unit testing的初衷,一些只是与被测程序有一些依赖关联的程序也要被测试,而且要构造非常复杂的数据,最后的结果很可能是降低了测试效率,最后还不一定能够达到测试目的。
那如何才能变得更加高效又能够达到测试的目的?这要感谢一个小伙伴的提醒,利用java反射就可以通过Junit测试代码来访问被测的类了。
该项目使用了Spring框架,于是我的第一版的测试代码是这样写的:
Test test = context.getBean("test");
Method getMethod = Test.class.getDeclaredMethod("getMethod", new Class[] {String.class});
getMethod.setAccessible(true);
Clazz obj = getMethod.invoke(test, "test");
可是这样写,最终居然发现我并不能取到Test类的实例。。我实在不知道我做错了什么。。结果java老鸟给我的意见仔细看看Spring的实现方式。结果我看了一下注册bean的java文件,是这样的:
<bean id="test" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="test" />
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,-RuntimeException,-DaoException,-NexasException
</prop>
</props>
</property>
</bean>
项目中使用了Spring的事务代理,之前的Test test = context.getBean(“test”);这种写法就有问题,取不到bean,经过一番google终于得到了问题的正解,于是有了Version 2:
Test test = (Test) getTargetObject(context.getBean("test"));
Method getMethod = Test.class.getDeclaredMethod("getMethod", new Class[] {String.class});
getMethod.setAccessible(true);
Clazz obj = getMethod.invoke(test, "test");
public static Object getTargetObject(Object proxy) throws Exception {
if (!AopUtils.isAopProxy(proxy)) {
return proxy;
}
return getTargetObject(getProxyTargetObject(proxy));
}
private static Object getProxyTargetObject(Object proxy) throws Exception {
Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
AopProxy aopProxy = (AopProxy) h.get(proxy);
Field advised = aopProxy.getClass().getDeclaredField("advised");
advised.setAccessible(true);
return ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
}
至此,一切搞定!学到就很多东西。