EasyMock:无效方法


68

我有一个方法,该方法在要测试的类的依赖项的类中返回void。

此类非常庞大,我仅使用其中的一种方法。我需要替换该方法的实现以进行测试,因为我希望它做一些不同的事情,并且需要能够访问该方法接收的参数。

我在EasyMock中找不到做到这一点的方法。我想我知道如何使用Mockito做到这一点doAnswer但是除非绝对必要,否则我不想添加其他库。

Answers:


93

如果我了解您要正确执行的操作,则应该可以使用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用户指南》解释了:

创建返回值或异常

有时我们希望我们的模拟对象返回一个值或引发在实际调用时创建的异常。从EasyMock 2.2开始,由expectLastCall()和返回的对象expect(T value)提供了andAnswer(IAnswer answer)[允许]指定IAnswer用于创建返回值或异常的接口的实现的方法。

IAnswer回调内部,可以通过传递给模拟调用的参数EasyMock.getCurrentArguments()。如果使用这些,则诸如重新排序参数之类的重构可能会破坏测试。你被警告了。


23

如果您只是希望在每次调用void方法时都调用它,然后在调用EasyMock.expectLastCall()之前调用它replay(),则Easymock将“记住”每次调用。

因此,我认为您不需要显式调用expect()(除外lastCall),因为您不会期望void方法(调用除外)中的任何内容。

谢谢克里斯!

StackOverflow的其他用户Burt Beckwith的“ Fun With EasyMock”是一篇不错的博客文章,提供了更多详细信息。摘录:

基本上,我倾向于使用的流程是:

  1. 创建一个模拟
  2. 呼叫expect(mock.[method call]).andReturn([result])每个预期的呼叫
  3. 打电话mock.[method call],然后EasyMock.expectLastCall()对每项预期无效呼叫
  4. 呼叫replay(mock)从“录制”模式切换到“播放”模式
  5. 根据需要注入模拟
  6. 调用测试方法
  7. 呼叫verify(mock)以确保所有预期的呼叫均已发生

1
我认为这个答案并不能解决问题-他不想只是断言该方法的期望,而是要替换其实现。
马特b

1
好一点,马特,另一方面,这篇文章帮助我意识到了为什么期望值方法在这里实际上并不适用。
彼得·威珀曼

5

如果您只想稍后访问参数,您可能还会喜欢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());

1

您可能要签出PowerMock。EasyMock基于代理反射API,这意味着一切都是代理,您只能测试接口,因此只能测试非最终方法和类。这可能对某些人有用,但是如果您要测试建成的世界,则需要更多的功能。

使用PowerMock,Java 5工具API消除了限制。无需编写要测试的对象的模拟对象实现(只是丑陋的IMO)。将PowerMock与Mockito(或JMockit)结合使用,您将真正参加比赛。

当然,还有另一个方向可以更容易地测试,即重写代码,如果可能的话,通常也是一个好主意。


-1

在这样的情况下,我发现在单元测试类中嵌套一个类并以这种方式覆盖具有特殊要求的方法是最好的方法。因此,如果您正在测试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
    }
}

然后在我的单元测试代码中,我只是使用该实例。就像对待其他模拟对象一样对待它。比混合库要容易得多,我同意这可能不是一个好主意。


1
已经考虑过了。但这是一个抽象类,因此我需要提供20个空方法实现或子类之一的子类,这可能会使其他开发人员在测试时感到困惑。
伊克·希门尼斯

哦好的。我不知道那是抽象的。如果您使用的是IDE(假设您使用的是Eclipse或NetBeans),它可以为您提供所有这些抽象方法,您只需在它们上面加一个注释,即可解释您的工作。这不是一个非常编程的解决方案,但是至少其他开发人员不会对此感到困惑。
马克W
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.