aop在接口测试中的应用
最近在接口测试过程中两次应用了aop,第一次解决了更改大量脚本之苦,第二次解决了增加重复代码之痛。下面详细说下场景及使用细节。
一、通过aop转换图片与分类id。
1、背景
多媒体平台上线后,图片空间要将数据迁移到平台统一管理。迁移开发要做两件事,首先是做接口兼容,就是原来调用图片空间的实现,走旧数据库,改成调用媒体平台的实现,走新数据库。接下来是把数据从老库迁移到新库,数据id要根据一定的规则进行转换。对于原先图片空间的接口我们已经做了测试,数据准备是按照原数据表的格式保存到 excel中的。
2、方案
从背景中可以分析得知,此次改动只是接口实现的改动,功能上并没有改变,所以我们只要保证原先的接口用例运行通过即可完成大部分的测试工作。
那如何最大程度上重用原先的用例呢,存在两个问题:
1)、准备数据问题,由于新老库在一段时间内存在增加同步程序,再加上smart的录制数据功能,可以基本解决这个问题。
2)、接口参数的问题,具体来说就是因为有些接口用到比如图片id与分类id,而这些id变了。
解决第二个问题有两种方案:
1)手动将这些id改掉,换成新的,涉及case 200+,改动量较大。
2)aop方法解决。用例脚本不变,写一个拦截类,对于参数id按规则进行转换。
好处:改动集中,量少,效率高。坏处:增加用例脚本复杂度,参数id与数据库不一致,日后维护人需要了解这个原理。
3、实现
我是一个喜欢偷懒的人,喜欢用到研究点技术的东西,加上时间比较紧,我选了用aop方式解决。
第一步:编写拦截类
public class AddSeqAspect { public Object doAround(ProceedingJoinPoint jp) throws Throwable { String methodName = jp.getSignature().getName(); Object[] args = jp.getArgs(); if (methodName.equals("queryXXXMethod")) { //通过旧id计算新id args[1] = getDirId((Long)args[1],(Long)args[0]); }... return jp.proceed(args); } }
这里使用 aop around 模式,把原来的参数id拿出来,经过转换后赋给新值,再调用原方法。开始我想用after模式来实现,后来测试后发现参数无法改变。
注意点:要注意处理这个接口被第二次调用时的判断,我是根据转换后id的特征来判断的,如果转换多于一次就会出错了。
第二步:spring aop配置,拦截目标接口,具体配置如下:
<bean id="addSeq" class="xx.xx.test.util.AddSeqAspect" ></bean> <aop:config> <aop:aspect id="AddSeqAspect" ref="addSeq"> <!--配置xxx.xxx包下所有类或接口的所有方法--> <aop:pointcut id="xxPoint" expression="execution(* xxx.xxx.*(..))" /> <aop:around pointcut-ref="xxPoint" method="doAround"/> </aop:aspect> </aop:config>
注意spring的配置文件要增加一些头信息
<beans xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd "
二、通过aop清理无用文件
1、背景
我们测试的接口有一个添加图片的,功能就是把图片保存到tfs 上,并将一些信息保存到数据库。我们接口脚本并没有去清理这些无用的文件,导致一段时间后tfs的磁盘满了。
2、方案
有两种方案
1)在每次需要清理的case中增加一行处理,记录返回结果中的tfs地址,然后在@After 方法中,将其删除。这个方案我以前经常使用,清理数据库信息以及缓存等我都是这么干的,但问题我更改30个以上case,体力活,有点烦。
2)通过aop after-returning 模式,通过一个静态变量记录接口返回值中的tfs地址。这个方案比较省事,很适合解决这类问题。
3、实现
第一步:编写拦截类
public class RecordResultAspect { public void doAfterReturn(Response<FileDO> result) { if(null != result && result.isSuccess()) { BaseTestCase.tfsPath = result.getResult().getUrl(); } } }
第二步:spring配置
<aop:after-returning pointcut-ref="addfilePoint" method="doAfterReturn" returning="result"/>
注:只列出了与上个例子不同的地方。
第三步:解决spring aop无法拦截无默认构造函数类的问题
参见: http://netfork.iteye.com/blog/286215
后记:
1)过程中调试也遇到了不少问题,花了不少时间,但有了成长,感觉还是值得的。
2)人有时懒点,也不是什么坏事情。