【问题标题】:How to mock a method which is called by another method using EasyMock?如何使用 EasyMock 模拟另一个方法调用的方法?
【发布时间】:2016-12-02 12:07:52
【问题描述】:

我需要在 void 方法中模拟一个方法。

这是我的示例代码:

class MyClass {

    public MyClass(Session s, Boolean b1, Boolean b2)

    void myMethod(some paramaters...) {

        // some code
        int count= setSize();
    }

    int setSize() {

        // some calculation....
        return size;
    }

现在在我的测试类中,我想模拟 setSize() 以返回我自己的值,比如 300

我确实喜欢:

MyClass mockclass = createNiceMock(MyClass.class);
EasyMock.expect(mockimplyZero.setBatchSize()).andReturn(Integer.valueOf(300));

mockclass.myMethod(parameters....)

当调用myMethod 时,它没有正确进入方法。 我认为这可能是 EasyMock 正在为 MyClass 构造函数设置默认值。如何正确模拟?

MyClass 中除了构造函数 myMethodsetSize 之外没有其他方法

【问题讨论】:

  • 提示:请阅读 java 命名约定。方法名称为 camelCase;领域也是如此;但是类名是大写的。这很重要;偏离这些标准会使您的代码更难为其他人阅读。

标签: java easymock


【解决方案1】:

您可以使用部分模拟来做到这一点。这是一个接近您的代码的示例。

首先是测试类。您将需要创建它的部分模拟。 getSize 应该被模拟,但 myMethod 应该被模拟,因为它是经过测试的方法。

此外,您经常需要调用构造函数来正确初始化类(经典模拟不会调用任何构造函数)。

class MyClass {

  private boolean b1;
  private boolean b2;

  public MyClass(boolean b1, boolean b2) {
    this.b1 = b1;
    this.b2 = b2;
  }

  int myMethod() {
    return getSize();
  }

  int getSize() {
    return 42;
  }

  public boolean getB1() {
    return b1;
  }

  public boolean getB2() {
    return b2;
  }
}

测试将如下所示

import org.junit.Test;

import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;

public class MyClassTest {

  @Test
  public void test() {
    // Create a partial mock by calling its constructor
    // and only mocking getSize
    MyClass mock = createMockBuilder(MyClass.class)
        .withConstructor(true, true)
        .addMockedMethod("getSize")
        .createMock();

    // Record that getSize should return 8 (instead of 42)
    expect(mock.getSize()).andReturn(8);

    // All recording done. So put the mock in replay mode
    replay(mock);

    // Then, these assertions are to prove that the partial mock is 
    // actually doing what we expect. This is just to prove my point. Your
    // actual code will verify that myMethod is doing was is expected

    // 1. Verify that the constructor was correctly called
    assertEquals(true, mock.getB1());
    assertEquals(true, mock.getB2());
    // 2. Verify that getSize was indeed mocked 
    assertEquals(8, mock.myMethod());

    // Check everything expected was indeed called
    verify(mock);
  }
}

工作完成。请注意,这不一定是设计不佳的标志。我在测试Template method pattern时经常使用它。

【讨论】:

    【解决方案2】:

    您不应该在 同一个 类上测试另一个方法时模拟 一个 方法。理论上你可以做到这一点(使用 Mokito spy 例如)。

    从这个意义上说,你在错误的层面上接近这个问题:你实际上不应该关心你的测试方法在你的测试类中调用了哪些其他方法。但是,如果您必须对测试进行调整,那么(例如)一种方法可以让您的测试代码在调用 mymethod() 之前设置该 size 字段。

    或者:您将关注点分开,并将“大小”部分移动到它自己的类 X 中。然后您的测试类可以保存 X 的实例;然后可以模拟该实例。

    长话短说:您想退后一步阅读一些有关如何使用 EasyMock 的教程。这不是你可以通过反复试验来学习的。

    【讨论】:

    • 哦,是吗...我应该以某种方式将此 setSize() 模拟为内部调用 Web 服务,并在测试期间失败。
    • 还有其他方法可以实现吗?
    • 非常取决于你真正想做的事情。但请相信我:您当前的方法不是合理的设计。不要试图强制执行这种方法;只是因为它是您当前在代码中拥有的那个。你最好退后一步,学习如何以“正确”的方式做这些事情;否则 EasyMock 对您的测试活动没有多大价值;最后让你觉得“这个单元测试的东西不起作用”。
    • 换句话说:也许你也想退后一步,学习做TDD(测试驱动开发)......因为为那些没有被写成可测试的代码编写测试总是更难。使用 TDD,这不会发生 - 因为您在编写生产代码之前编写测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多