我想模拟当 CompletableFuture
成功完成时正在调用一些代码。
我有这堂课:
public class MyClassImplementRunner implements Runnable {
private final String param1;
public MyClassImplementRunner(String param1) {
this.param1 = param1;
}
public static CompletableFuture<Void> startAsync(String param1) {
return CompletableFuture.runAsync(
new MyClassImplementRunner(param1)).whenComplete(
(response, throwable) -> {
//some code when complete
});
@Override
public void run () {
//the runnable code
}
}
}
在我的 Junit(使用 Mockito 和 Java 8)中,我需要模拟它
//some code when complete
当 Future 成功完成时调用。
您能否就如何实现这一目标提供一些指示?
我的第一个倾向是
not to mock this
:看起来startAsync
是 MyClassImplementRunner 的公共 API 的一部分,您应该一起测试这些部分。在像 MyClassImplementRunnerTest 这样的测试类中,将被测系统视为 MyClassImplementRunner 而不会尝试将其拆分是有意义的。否则,很容易忘记what you're testing
,包括what is real
与what is a mock
。如果 MyClassImplementRunner 正在寻找任何
external
条件,您可以模拟该依赖项,这可能会导致您的 CompletableFuture 立即返回;但是,您只向我们展示了一个字符串参数。也就是说,
startAsync
可能包含您希望在没有真正的 MyClassImplementRunner 的情况下彻底测试的逻辑。在这种情况下,您可以创建一个用于测试的重载,可能具有有限的可见性或 test-only annotations 以指示不应在生产中调用它。通过拆分,您现在可以在测试中运行
startAsync(new Runnable())
来模拟立即成功的任务,并运行startAsync(() -> { throw new RuntimeException(); })
来模拟立即失败的任务。这允许您独立于 MyClassImplementRunner 测试startAsync
。为测试重构或引入仅测试方法似乎并不明智,这是一个公平的评估:纯粹地说,MyClassImplementRunner
should
完全按照消费者运行它的方式进行测试,无需模拟。但是,如果您说在测试中使用与 MyClassImplementRunner 不同的 Runnable 运行会更方便,那么您可以控制代码,并且可以通过在代码中包含适当的灵活性(“测试接缝”)来为此做好准备你控制。事实上,如果startAsync
是一个足够独立的方法,它可以采用任意 Runnable,那么您可以选择将其分离为单独测试的单独方法。