更完整的问题是,给定一个期望回调作为参数的依赖项,如何编写涵盖回调逻辑的单元测试 和 仍设法模拟依赖?
public class DoStuff {
public void runThis(Runnable callback) {
// call callback
}
}
public class ClassUnderTest {
private DoStuff stuffToDo;
public void methodUnderTest() {
this.stuffToDo.runThis(/*a runnable with some logic*/)
}
}
在上面的例子中,我会嘲笑 stuffToDo
因为我应该验证方法调用的调用和模拟输出。然而,嘲笑 runThis
导致回调逻辑未被测试。此外,回调逻辑似乎应该是私有的,所以我不希望直接测试它;或许这对我来说是个误解。
由于回调被相当广泛地使用,我希望有一种常用的方法来测试它们,但我还没有找到它。
你不能在一次测试中。如果你嘲笑某事,那就是 嘲笑,这意味着它只能验证参数并模拟返回值(在测试中配置)。
实际上,模拟某事的全部意义在于测试单独使用模拟的内容。如果你想进行单元测试 DoStuff
,您不必担心使用某些可能会或可能不会正常工作的回调实现。你嘲笑回调,所以你不必担心它。
通过单独测试回调代码,您仍然可以进行良好的测试, 和 单独测试回调用户(使用mock作为回调),并且可能通过抛出集成测试进行良好测量,其中您将完全配置的组件作为一个整体使用。
这里基本上你想测试这个类 做东西。这意味着您需要对DoStuff中的所有方法进行彻底测试,对吧?所以在这种情况下,你需要做的是,而不是嘲笑 stuffToDo 本身, 注入 一个模拟的Runnable into stuffToDo。然后检查您的runnable是否成功执行。
但是如果你在课堂上有其他功能,你可以进行单独测试并模拟它们。
在您的特定情况下,听起来您已经测试过了 DoStuff
(或者不再关心,因为它被嘲笑)现在特别是对特定的单元测试 Runnable
你设计的。在这种情况下, callback
听起来就像你想要测试的一样,有人可能想要直接对数据库策略或内存策略进行单元测试。
如果这是你正在尝试的,你要么可以在一个黑盒子里测试它,然后再进行测试 ClassUnderTest
尽你所能。或者,您可以在特定的Runnable上创建测试工具。如果要发布此代码并且不希望使测试工具可访问,则可以将测试工具方法设为私有,并专门与单元测试程序集共享其详细信息。
看 这里 有关如何制作朋友集会的信息。我通常签署我的单元测试代码,以便我不必使用命令行编译器。我想这取决于你的构建环境。
如果只是无条件地调用Runnable的假DoStuff怎么样?
然后你只需要感知效果 - 如果你的回调被执行就应该观察到的变化。
如果您使用EasyMock,则可以使用 andStubAnswer
调用runnable。
doSomethingMock.runThis(runnable);
expectLastCall().andStubAnswer(new IAnserable<Void>() {
Runnable runnable = (Runnable)getCurrentArguments()[0];
runnable.run();
return null;
});
我想其他的模拟框架包含类似的东西。