慕桂英546537
如何用mockito+spring进行单元测试(2)以前写过一篇blog,写得不是很详细。这次清明节在家好好的整理了下思路,把相关的细节重写下来。很奇怪这些内容在google上找不到,也许是太基本了吧。为了理解mockito,必须先明白mock测试的原理,它分成以下几个步骤:建立mock;将mock和待测试的对象连接起来;在mock上设置预期的返回值;开启replay模式,准备记录实际发生的调用;进行测试;验证测试结果,调用顺序是否正确,返回值是否符合期望;本文主要讲第一步和第二步。对于Mockito而言,有两种方式创建:1. mock为一个interface提供一个虚拟的实现,2. spy为object加一个动态代理,实现部分方法的虚拟化。假设待测试的class声明如下:public class Svc{DaoInterface dao1;DaoInstance dao2;…你可以用如下的声明得到一个Interface的mock,或者一个实例的spy,并把它注入到测试对象中:private Svc svc;private DaoInterface mockdao;@Beforepublic void setup(){mockdao = mock(DaoInterface.class);svc.setDao1(mockdao);}private Svc svc;private DaoInstance spydao ;@Beforepublic void setup(){tmp= new DaoInstance ();spydao = spy(tmp);svc.setDao2(spydao);}请注意到spy和mock的不同。但是spy并不是很好的实践,因为它意味着你的代码不能很好的将变化的部分分离开来。因此最好只在那些历史遗留系统上使用。上面这种方式并不唯一的途径。为了避免重复代码,Mockito提供了几个注解:@Mock,被标注的属性是个mock@Spy,被标注的属性是个spy,需要赋予一个instance@InjectMocks,将本test中的mock或者spy注入到被标注的属性中,根据构造函数的参数名,或者setter,或者私有属性名。最后在setup中调用MockitoAnnotations.initMocks(this);就免去了代码的编写。如下所示:private @InjectMocks Svc svc;private @Mock DaoInterface dao1;@Beforepublic void setup(){//mockdao = mock(DaoInterface.class);//svc.setDao1(mockdao);MockitoAnnotations.initMocks(this);}private @InjectMocks Svc svc;private @Spy DaoInstance dao2=newDaoInstance() ;@Beforepublic void setup(){// tmp= new DaoInstance ();// spydao = spy(tmp);// svc.setDao2(spydao);MockitoAnnotations.initMocks(this);}如果你使用spring,上述代码还可以进一步简化,因为Mockito提供了factory的方法用来创建mock和spy。正常的bean声明 <bean id=”svc” class=”Svc”><bean id=”dao1” class=”…”><bean id=”dao2” class=”…”>mock<bean id="dao1" class="org.mockito.Mockito" factory-method="mock"><constructor-arg value="DaoInterface"></constructor-arg></bean>请注意到svc不变化,mock将自动注入进入。这是因为spring的bean容器,如果id一样,后声明的bean会覆盖前面的bean。spy<bean id="daoInst" class="DaoInstance"></bean><bean id="dao2" class="org.mockito.Mockito" factory-method="spy"><constructor-arg ref="daoInst"></constructor-arg></bean>同样svc不变化,直接注入。请注意spy需要获得一个实例。