Mockito Spy - 调用构造函数之前的存根

2022-09-01 09:50:48

我正在尝试监视对象,并且我想在构造函数调用它之前存根构造函数调用的方法。
我的班级看起来像这样:

public class MyClass {
    public MyClass() {
         setup();
    }

    public void setup() {

    }
}

不得调用设置方法。好吧,我如何监视此方法(和存根设置,以便它不执行任何操作)?
它适用于模拟方法,但我想进行单元测试,因此我需要非常其他的方法。MyClass


为什么需要存根设置方法以便它什么都不做:
我正在编写一个乐高机器人(lejos),我在设置中放入了一些机器人需要工作的代码。但是,当我在TinyVM(安装在机器人上的VM)之外调用它时,java会崩溃,因为它的VM尚未正确初始化(因为测试在我的PC上运行)。对于单元测试,设置并不重要。
我无法存根类/方法设置调用,因为它们中的一些是公共静态最终变量。


答案 1

要直接回答您的问题,您不能使用 Mockito 来存根从构造函数调用的方法。Mockito 需要一个类的实例,然后才能开始模拟,而且你还没有给自己一种创建用于测试的实例的方法。

更一般地说,如 Effective Java 项 17 中所述,不应从构造函数中调用可重写的方法。例如,如果这样做,则可以在子类中提供覆盖,该子类引用字段但在设置字段之前运行。它可能不会让你在这里遇到麻烦,但这在Java中是一个坏习惯。finalfinal

幸运的是,您可以非常轻松地重构代码以执行此操作:

public class MyClass {
  public MyClass() {
    this(true);
  }

  /** For testing. */
  MyClass(boolean runSetup) {
    if (runSetup) {
      setup();
    }
  }

  /* ... */
}

为了使它更加明显,您可以将单参数构造函数设为私有,并提供一个工厂方法:MyClasspublic static

/* ... */
  public static MyClass createForTesting() {
    return new MyClass(false);
  }

  private MyClass(boolean runSetup) {
/* ... */

尽管一些开发人员认为用主要用于测试的方法编写任何代码都是一种不好的做法,但请记住,您负责代码的设计,并且测试是您绝对知道您需要适应的少数消费者之一。虽然在“生产”代码中避免显式测试设置仍然是一个好主意,但为了测试而创建额外的方法或重载通常会使代码整体更清晰,并且可以大大提高测试覆盖率和可读性。


答案 2
  1. 使用PowerMock。

  2. 导入库后,将其设置为使用不得调用的实例方法操作要模拟的类。

这样:

@RunWith(PowerMockRunner.class)
@PrepareForTest({<Other classes>, Myclass.class})
  1. 在测试开始时禁止显示该方法。

这样:

suppress(method(Myclass.class, "setup"));
  1. 在测试中根据需要自定义 setup() 方法的行为。

这样:

doAnswer(new Answer<Void>() {
      @Override
      public Void answer(InvocationOnMock invocation) throws Throwable {
           // code here
           return null;
      }
 }).when(Myclass.class, "setup");

推荐