背景介绍:
今年我们产品线对我们去年线上的遗留bug做了分析,发现线上的遗留问题基本上是一些无法测试到的异常流程或者依赖的其他应用有异常引起的,普通的正常功能测试已经很难发现那些问题,于是我们今年提出了一个容错测试的目标,希望能够解决这类问题的测试瓶颈.
我们的目标:
<!--[if !supportLists]-->2 <!--[endif]-->测试各种错误异常情况下系统的反应
<!--[if !supportLists]-->2 <!--[endif]-->通过自动化的手段运行
为了说明后面的内容,先看一个简单的例子,有下面的被测代码:
接口:
public interface IHello { public int hello(); } |
实现:
public class Hello implements IHello { @Override public int hello() { System.out.println("Hello is print!"); return 1; } } |
现有方案介绍:
<!--[if !supportLists]-->1. <!--[endif]-->运用eclipse
debug,使用display功能修改值
问题:无法自动化
<!--[if !supportLists]-->2. <!--[endif]-->编写mock的测试bean
问题:切入时间比较难控制,因为真实环境下的bean依赖如下图,用mock框架很难控制bean的注入点.
新的方案(基于AOP的实现):
采用AOP的方式来插入mock对象:
实现细节(限于篇幅,做了一定精简)
<!--[if !supportLists]-->1. <!--[endif]-->切面处理类,在触发点加上特殊的处理逻辑:
定义参数,可以注入预期值,延迟,sleep等
注入的代码,以注入预期对象为例,其他(sleep,exception)雷同省略
<!--[if !supportLists]-->2. <!--[endif]-->如果需要多线程处理,则增加多线程处理方法.此部分非本文重点,只是简单说明一下结构如下,单个线程(MockThread)里可以注入mock对象&预期值&校验器,然后通过ThreadFactory管理各个线程及调度策略,主要使用在注入延迟后,进行一些并发操作的校验
<!--[if !supportLists]-->3. <!--[endif]-->使用过程,大体分为3步,如下:
<!--[if !supportLists]-->a) <!--[endif]-->配置:
配置切面,选择mock触发点,配置连接点的逻辑,选择处理方式
<bean id="mockAspect" class="com.taobao.azeroth.util.MockTestAspect" > <property name="sleepTime" value="0"/> <property name="flag" value="false"/> </bean> <aop:config proxy-target-class="false" > <aop:pointcut id="springTestPointcut" expression="execution(* com..Hello.hello(..))" /> <aop:aspect id="aspectSpringSleep" ref="mockAspect" order="100"> <aop:around method="mockMethod" pointcut-ref="springTestPointcut" /> </aop:aspect> </aop:config> |
<!--[if !supportLists]-->b) <!--[endif]-->脚本:
配置切面参数&调用被测试方法
<!--[if !supportLists]-->c) <!--[endif]-->执行策略:
是否要多线程&构造单个线程的参数&配置执行策略,运行
@Test public void test_01_thread_run(){ ThreadFactory thFac=new ThreadFactory(); //配置切面信息 mockAspect.setMockResult(11); ThreadTest th=new ThreadTest(); th.setOwnerBean(hello); th.setMethodName("hello"); th.setMockAspect(mockAspect); th.setThreadMockFlag(true); //一个线程可以有n个校验服务 AssertService as=new AssertService(); //增加线程中的验证方法,直接可以定义 as.setCheckMethod(this, "checkResult"); th.addAssertService(as); //通过传单个mock thread来传参 thFac.addThread(th); //同时启动5个线程来测试 thFac.startThreads(5); } public void checkResult(Integer result){ System.out.println("传入设置actual值得方法"); result=result+1; assertThat("验证",result,greaterThan(10)); } |
总结:
使用AOP的方式来注入mock内容,可以使我们的测试代码更清晰,利于维护管理,也可以更好的扩展我们的mock时要进行的操作.
|