公司开发遵循SCRUM,SCRUM倡导测试驱动开发,即Test-driven-development (TDD)。不可否认TDD是一个很好的东西,但是严格遵循TDD需要程序员付出更多的时间构造测试用例和维护测试用例,这势必是一种成本的增加,许多公司没有坚决执行TDD往往是由于项目的成本估算以及程序员的个人习惯。个人认为,长远来看使用TDD的开发方式可以起到磨刀不误砍柴工的作用,达到事半功倍的效果。
做Java开发最常用的自动化测试框架就是Junit,关于JUnit的资料有很多,这里就不一一列举了。简单的测试用例谁都会写,但是如果要构造拥有低权限访问控制修饰符修饰的属性并且没有提供getter和setter方法的对象参与的测试用例有一点点麻烦,这里的低权限访问控制修饰符指得是private,default和protected.
在使用Spring的场景下,经常会通过Spring来构造出许多这样的对象(当然,不仅限于用Spring构造这样的对象,但很常见的场景便是用Spring生成)。
在JUnit编写Test case时可以采用两种方法进行反射获取对象的低访问控制修饰符修饰的属性。以下分别是两种方式的示例代码,被测试对象如下:
@Component("XXXService") public class XXXService{ @Autowired private Provider provider; }这只是一个普通的不能再普通的Spring bean,里面只有一个private属性 provider。注意:由于是要测试Spring的bean,所以在测试类里要先获得一个Spring的ApplicationContext对象,这个对象的获取要依据测试本身上下文来选择采用哪种ApplicationContext的实现类,在这里就不一一举例,只是假设测试类已经获得了一个ApplicationContext对象。
一.通过标准的Java reflection api在测试类中获得provider属性。
@Test public void retrievePrivateAttributeByStandard(){ //Retrieve the spring bean instance. XXXService service = (XXXService)applicationContext.getBean("XXXService"); //Retrieve the private attribute by name. Field providerField= service.getClass().getDeclaredField("provider"); //It's required to set the accessble flag to true if the attribute is under private,protected or default. providerField.setAccessible(true); //Retrieve the attribute by the instance of the Spring bean. Provider provider = (Provider)providerField.get(service); //You can use the private property to continue build your test case. }注意:1. providerField.setAccessible(true);必须要设置,否则还是不能访问该属性。
2.Provider provider = (Provider)providerField.get(service);这一步的时候要求传入的不是一个动态代理,Spring在解析接口的时候采用动态代理机制,如果是这样会报错,所以如果传入的是一个实现类的实例是没有问题的,但是如果Provider是个接口,就会报错,关于处理动态代理的问题,这里先不讨论,后续我会更新。
二.通过Spring的反射工具类来获得provider属性。
@Test public void retrievePrivateAttributeByUtil(){ //Retrieve the spring bean instance. XXXService service = (XXXService)applicationContext.getBean("XXXService"); //Retrieve the private attribute according to ReflectionTestUtils. Provider provider = (Provider)ReflectionTestUtils.getField(service,"provider"); //You can use the private property to continue build your test case. }这个反射工具类是 ReflectionTestUtils,参阅它的API,对于 ReflectionTestUtils.getField(Object target,String name)方法的一句很重要的描述: