我有以下代码:
private MyService myService;
@Before
public void setDependencies() {
myService = Mockito.mock(MyService.class, new StandardServiceAnswer());
Mockito.when(myService.mobileMethod(Mockito.any(MobileCommand.class), Mockito.any(Context.class)))
.thenAnswer(new MobileServiceAnswer());
}
Run Code Online (Sandbox Code Playgroud)
我的意图是,所有对被嘲笑者的召唤myService都应以标准方式回答.但是mobileMethod,应以特定方式回答(公开的)呼叫.
我发现的是,当我到达行添加调用的答案mobileMethod而不是附加时MobileServiceAnswer,Java实际上是在调用myService.mobileMethod,这会导致NPE.
这可能吗?看起来应该可以覆盖默认答案.如果有可能,这样做的正确方法是什么?
这是我的Answers:
private class StandardServiceAnswer implements Answer<Result> {
public Result answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Command command = (Command) args[0];
command.setState(State.TRY);
Result result = new Result();
result.setState(State.TRY);
return result;
}
}
private class MobileServiceAnswer implements Answer<MobileResult> {
public MobileResult answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
MobileCommand command = (MobileCommand) args[0];
command.setState(State.TRY);
MobileResult result = new MobileResult();
result.setState(State.TRY);
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
Jef*_*ica 27
两个无关的惊喜一起导致了这个问题:
Mockito.any(Class) 实际上并不返回该类的对象.它返回null并在名为ArgumentMatcherStorage的秘密内部匹配器堆栈上隐藏 "忽略参数并接受任何东西"匹配器.该参数值实际上将为null,但在大多数情况下,您将看不到它.
声明when(foo.bar()).thenReturn(baz)实际上foo.bar()总是在呼唤.通常情况下,这没有任何副作用 - 特别是如果你正在对其第一个动作链进行存根 - 所以你没有注意到它.
在存根期间,Java会调用您的真实答案,并尝试调用setState基于matcher的(null)参数.基于Java评估顺序,这是有道理的:Mockito将您的答案称为被测系统调用您的答案,因为Mockito无法知道mobileMethod紧接呼叫之前的呼叫when.它还没有到达那里.
答案是使用"doVerb"的方法,比如doAnswer,doReturn和doThrow,我喜欢称之为"尤达语法".因为这些包含when(object).method()而不是when(object.method()),Mockito有机会停用您之前设定的期望,并且您的原始答案永远不会被触发.它看起来像这样:
MyService myService = Mockito.mock(MyService.class, new StandardServiceAnswer());
Mockito.doAnswer(new MobileServiceAnswer())
.when(myService).mobileMethod(
Mockito.any(MobileCommand.class), Mockito.any(Context.class));
Run Code Online (Sandbox Code Playgroud)
值得注意的是,异常是您的覆盖不起作用的唯一原因.在正常情况下,"when-thenVerb"对于覆盖绝对没问题,并且会回溯先前的操作,以免甩掉连续的动作.thenReturn(...).thenThrow(...).同样值得注意的是,when(mobileMethod(command, context))如果没有抛出异常,它会发生变化command并且context在存根期间会发生微小的测试差距.
有些开发人员甚至比"when-thenVerb"语法更喜欢"doVerb-when"语法,因为它具有从不调用其他模拟的好行为.我们欢迎您得出相同的结论 - "doVerb"会执行"when-thenVerb"所做的一切,但在模拟和间谍中覆盖行为时更安全.我更喜欢"when"语法本身 - 它读起来更好一些,并且它会进行类型检查返回值 - 只要你记得有时候"doVerb"是获得你需要去的地方的唯一方法.
| 归档时间: |
|
| 查看次数: |
13106 次 |
| 最近记录: |