模拟抽象方法,但不模拟类构造函数



我有一个类似于下面的抽象类的场景。我想模拟通过构造函数提供的RandomNumberGenerator实例,我想编写一个单元测试来测试 doSomethingRandomLotsOfTimes 方法中的逻辑。

有没有办法用 mockito/另一个框架来做到这一点?

public abstract class MyClass {
    private final RandomNumberGenerator randomNumberGenerator;
    public MyClass(RandomNumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }
    public abstract void doSomething(int x);
    public void doSomethingRandomLotsOfTimes() {
        for(int i=0; i<10; i++) {
            int r = randomNumberGenerator.next();
            doSomething(r);
        }
    }
}

我的测试

@Test
public void testItDoesSomething10Times() {
    // Given
    when(randomNumberGenerator.next()).thenReturn(0);
    MyClass myClass = ...
    // When
    myClass.doSomethingRandomLotsOfTimes();
    // Then
    // Assert Something
}

你的类更容易通过组合实现:

public final class MyClass {
    private final RandomNumberGenerator randomNumberGenerator;
    private final IntConsumer somethingDoer;
    public MyClass(
            RandomNumberGenerator randomNumberGenerator,
            IntConsumer somethingDoer) {
        this.randomNumberGenerator = randomNumberGenerator;
        this.somethingDoer = somethingDoer;
    }
    public void doSomethingRandomLotsOfTimes() {
        for(int i=0; i<10; i++) {
            int r = randomNumberGenerator.next();
            somethingDoer.consume(r);
        }
    }
}

现在,您可以编写一个单元测试来断言MyClass工作,并且它会调用somethingDoer预期的次数;您可以编写单元测试来断言IntConsumer工作。

但是您不必担心以下情况:

  • 脆弱的基类问题。
  • 粗心/恶意地实现MyClassdoSomething()调用doSomethingRandomLotsOfTimes()(好吧,也许你会这样做,这要困难得多......
  • "设计和记录继承">

等。

没有办法直接实例化抽象类。必须实例化扩展抽象类的非抽象类。

声明一个非抽象类,该类扩展单元测试类中的抽象类(例如public static class blam extends MyClass(,并提供所有抽象方法的空实现。

一旦你有一个可以实例化的类,创建 RandomNumberGenerator 类的间谍。间谍允许您测试间谍中的方法是否被调用。

创建一个blam实例,并将间谍随机数生成器作为构造函数参数传递。

最新更新