现在需要对A进行单测,但是C需要依赖于外部环境,而这个环境需要复杂而且不稳定的数据库。怎么办呢?这时你就需要mock掉C。 第一步你需要在appctx文件中申明:
需要注意的是bean的id必须要和A和B中autowire时使用名字一致。或者用类型也行。 然后在单测case中用@Mock或者@Resource引入sercieC。接着在单测case的Setup中调用如下语句。
MockitoAnnotations.initMocks(this);
这时你测试A的方法,A访问B,B访问C时,调用会落在mockito生成的一个代理上。这个时候所调用的任何方法都会返回null。
这可能不是你期望的,你可能期望在A用到的那些些方法上,输入某个值时返回某个特定的值。这个时候你需要: when().then();
如果这还不够,你希望他输入某个值的时候返回特定值,如果输入的值不是特定值的时候,返回正常逻辑的值,你需要spy,并传入一个serviceC的实现。 这个方法也解决了那个对于不mock的方法进行返回的问题
为了理解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; @Before public void setup(){ private Svc svc; private DaoInstance spydao ; @Before public void setup(){ mockdao = mock(DaoInterface.class); tmp= new DaoInstance (); svc.setDao1(mockdao); }
请注意到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; @Before private @InjectMocks Svc svc; private @Spy DaoInstance dao2=new DaoInstance() ; spydao = spy(tmp); svc.setDao2(spydao); } public void setup(){ @Before //mockdao = mock(DaoInterface.class); public void setup(){ //svc.setDao1(mockdao); MockitoAnnotations.initMocks(this); } // tmp= new DaoInstance (); // spydao = spy(tmp); // svc.setDao2(spydao); MockitoAnnotations.initMocks(this); } 如果你使用spring,上述代码还可以进一步简化,因为Mockito提供了factory的方法用来创建mock和spy。 正常的 因篇幅问题不能全部显示,请点此查看更多更全内容