我有一个方法在一个类中返回 void,该类是我要测试的类的依赖项。
这个类很大,我只使用它的这个单一方法。我需要为测试替换此方法的实现,因为我希望它做一些不同的事情,并且我需要能够访问此方法接收的参数。
我在EasyMock中找不到这样做的方法。我想我知道如何使用 Mockito 来做到这一点,但doAnswer
除非绝对必要,否则我不想添加另一个库。
我有一个方法在一个类中返回 void,该类是我要测试的类的依赖项。
这个类很大,我只使用它的这个单一方法。我需要为测试替换此方法的实现,因为我希望它做一些不同的事情,并且我需要能够访问此方法接收的参数。
我在EasyMock中找不到这样做的方法。我想我知道如何使用 Mockito 来做到这一点,但doAnswer
除非绝对必要,否则我不想添加另一个库。
如果我理解您想要正确执行的操作,您应该可以使用andAnswer()
:
mockObject.someMethod(eq(param1), eq(param2));
expectLastCall().andAnswer(new IAnswer() {
public Object answer() {
//supply your mock implementation here...
SomeClass arg1 = (SomeClass) getCurrentArguments()[0];
AnotherClass arg2 = (AnotherClass) getCurrentArguments()[1];
arg1.doSomething(blah);
//return the value to be returned by the method (null for void)
return null;
}
});
创建返回值或异常
有时我们希望我们的模拟对象返回一个值或抛出一个在实际调用时创建的异常。从 EasyMock 2.2 开始,对象返回
expectLastCall()
并expect(T value)
提供andAnswer(IAnswer answer)
允许 [您] 指定IAnswer
用于创建返回值或异常的接口的实现的方法。在
IAnswer
回调中,传递给模拟调用的参数可以通过EasyMock.getCurrentArguments()
. 如果你使用这些,像重新排序参数这样的重构可能会破坏你的测试。你被警告了。
如果您只是在每次期望调用 void 方法时调用它,然后在调用EasyMock.expectLastCall()
之前调用replay()
,Easymock 将“记住”每次调用。
因此,我认为您不需要显式调用expect()
(除了lastCall
),因为除了调用之外,您对 void 方法没有任何期望。
谢谢克里斯!
StackOverflow 用户Burt Beckwith的“Fun With EasyMock”</a>是一篇很好的博文,提供了更多详细信息。值得注意的摘录:
基本上我倾向于使用的流程是:
- 创建一个模拟
- 呼叫
expect(mock.[method call]).andReturn([result])
每个预期呼叫- call
mock.[method call]
,然后EasyMock.expectLastCall()
对于每个预期的 void 调用- 调用
replay(mock)
从“录制”模式切换到“回放”模式- 根据需要注入模拟
- 调用测试方法
- 打电话
verify(mock)
以确保所有预期的电话都发生了
如果您只想稍后访问参数,您可能还会喜欢EasyMock 2.4 新增的Captures类。
您可以使用“Capture”类的实例代替匹配器。当您的模拟方法被调用时,Capture 实例将存储调用它的参数。
Capture<ChartPanel> captured = new Capture<ChartPanel>();
// setChartPanel is going to be called during execution;
// we want to verify some things about the ChartPanel
// instance it's invoked with
chartMock.setChartPanel(capture(captured));
replay(chartMock);
ufdm.setChartAnnotater(chartMock);
// afterPropertiesSet triggers the setChartPanel call...
ufdm.afterPropertiesSet();
verify(chartMock);
// verify some things about the ChartPanel parameter our
// mock object was invoked with
assertSame(plot, captured.getValue().getChart().getPlot());
您可能想查看 PowerMock。EasyMock 基于代理反射 API,这意味着一切都是代理,您只能测试接口,因此只能测试非最终方法和类。这可能对某些人有用,但如果你正在测试构建的世界,你将需要更多的力量。
使用 PowerMock,Java 5 检测 API 消除了这些限制。无需编写要测试的对象的模拟对象实现(只是丑陋的 IMO)。将 PowerMock 与 Mockito(或 JMockit)结合使用,您将真正参加比赛。
当然,还有另一个方向是重写代码以便更容易测试,如果可能的话,这通常也是一个好主意。
在这种情况下,我发现在我的单元测试类中创建一个嵌套类并以这种方式覆盖具有特殊要求的方法是最好的方法。因此,如果您正在测试ClassA
哪个方法具有您需要访问的参数,您可以执行以下操作:
class MockClassA extends ClassA {
@Override
void specialMethod(String param1, String param2) {
// do logging or manipulation of some sort
super.specialMethod(param1,param2); // if you need to
}
}
在我的单元测试代码中,然后我只使用这个实例。只需将其视为任何其他模拟对象即可。比混合库容易得多,我同意这可能不是一个好主意。