我有一个类似于下面的抽象类的场景。我想模拟通过构造函数提供的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
工作。
但是您不必担心以下情况:
- 脆弱的基类问题。
- 粗心/恶意地实现
MyClass
从doSomething()
调用doSomethingRandomLotsOfTimes()
(好吧,也许你会这样做,这要困难得多...... - "设计和记录继承">
等。
没有办法直接实例化抽象类。必须实例化扩展抽象类的非抽象类。
声明一个非抽象类,该类扩展单元测试类中的抽象类(例如public static class blam extends MyClass
(,并提供所有抽象方法的空实现。
一旦你有一个可以实例化的类,创建 RandomNumberGenerator 类的间谍。间谍允许您测试间谍中的方法是否被调用。
创建一个blam
实例,并将间谍随机数生成器作为构造函数参数传递。