Mockito:方法的返回值取决于其他方法

pav*_*lou 7 java junit mockito

在我的单元测试中,我需要模拟不同方法之间的接口nextItem()isEmpty()方法:

public interface MyQueue {
    Item nextItem();
    boolean isEmpty();
    //other methods
    ...
}
Run Code Online (Sandbox Code Playgroud)

我对mock的要求是,isEmpty()最初应该返回false,但是在nextItem()调用之后isEmpty()应该返回true.因此,我正在用一个项目模拟一个队列.

  1. 使用mockito实现这种模拟的最简单方法是什么?
  2. 我可以实现额外的要求:调用nextItem()第二次,第三次等等会导致特定的异常吗?

PS我不想为测试提供我的接口的完整实现,因为其中有其他方法,导致难以理解和冗长的代码.

Ass*_*lov 9

您可以使用thenAnswer()实现这一目标,Mockito文档认为该功能存在争议:

另一个有争议的特征,原本没有包含在Mockito中.我们建议仅使用toReturn()或toThrow()的简单存根.这两个应该足以测试/测试任何干净简单的代码.

这是答案:

private boolean called = false;

when(mock.nextItem()).thenAnswer(new Answer() {
 Object answer(InvocationOnMock invocation) {   
     called = true;       
     return item;
 }
when(mock.isEmpty()).thenAnswer(new Answer() {
 Object answer(InvocationOnMock invocation) {          
     return called;
 }
});
Run Code Online (Sandbox Code Playgroud)


Tom*_*icz 6

这是一个简单的例子:

//given
MyQueue mock = mock(MyQueue.class);

given(mock.isEmpty()).willReturn(false, true);
given(mock.nextItem()).willReturn(someItem);

//when
mock.isEmpty();   //yields false
mock.nextItem();  //yields someItem
mock.isEmpty();   //yields true

//then
InOrder inOrder = inOrder(mock);
inOrder.verify(mock).isEmpty();
inOrder.verify(mock).nextItem();
inOrder.verify(mock).isEmpty();
Run Code Online (Sandbox Code Playgroud)

willReturn(false, true)意思是:返回false上一次调用和true在第二.InOrderobject用于验证调用顺序.更改订单或删除nextItem()呼叫,测试将失败.

或者,您可以使用以下语法:

given(mock.isEmpty()).
        willReturn(false).
        willReturn(true).
        willThrow(SpecialException.class);
Run Code Online (Sandbox Code Playgroud)

如果你需要更强大的模拟语义,你可以引入重炮 - 自定义答案回调:

given(mock.isEmpty()).willAnswer(new Answer<Boolean>() {
    private int counter = 0;
    @Override
    public Boolean answer(InvocationOnMock invocation) throws Throwable {
        switch(++counter) {
            case 1: return false;
            case 2: return true;
            default: throw new SpecialException();
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

但这很容易导致无法维护的测试代码,请谨慎使用.

最后,您可以通过仅模拟选定的方法来监视您的真实对象.