我正在开发一个简化控制台应用程序创建的框架。我的框架是用Scala编写的,我使用ScalaTest和Mockito进行单元测试。
我需要能够模仿java.io.Console
,但它已被宣布为最终版。我试图实现100%的单元测试覆盖率目前这是阻止我的唯一因素 - 功能和单元测试。
到目前为止,我还没有能够解决任何问题,我只是无法想到这样做的方法。它没有实现我可以嘲笑的界面,这个方法在其他任何地方都不可用,显然我无法扩展它。我想也许有一个解决方案可能涉及调用readLine
和readPassword
等方法的某种动态方法,但我没有足够的经验来到任何地方还有那种思路!
答案 0 :(得分:1)
您应该创建自己的界面来包装与java.io.Console
的所有互动,例如
public interface ConsoleService {
...
}
只要您只通过ConsoleService
的实例与控制台进行交互,您就可以像往常一样模拟ConsoleService
并测试99%的代码。 ConsoleService
接口成为应用程序的边界,用于整个应用程序的功能测试和直接与之交互的类的单元测试。
现在我们已将问题的范围缩小为“我如何测试ConsoleService
实施”,我们需要获得一些创意。例如,您可以将控制台输出重定向到文件并检查文件的内容。您可能甚至不想测试Scala中的ConsoleService
;您可以使用ConsoleService
编写骨架应用程序,然后使用您选择的脚本语言在您喜欢的操作系统上启动真实的控制台,与您的骨架应用程序交互并以这种方式测试ConsoleService
。你可以在这里获得创意(和hacky)因为:
ConsoleService
实现不需要进行太多改变的程度,即您的古怪测试解决方案对未来的开发人员来说不会是一个很大的负担。由于这些原因,显而易见的是保持ConsoleService
包装非常薄是个好主意,因为其中的任何逻辑都将通过奇怪的ConsoleService
进行测试测试,不是很好的友好Scala测试。通常直接委派给java.io.Console
方法已经足够了,但是您应该允许应用程序的功能测试驱逐ConsoleService
接口而不是做出任何假设(您的功能测试断言可能依赖于与模拟ConsoleService
,或者可能是存根的状态,测试ConsoleService
的实现,你可以在测试中控制它。)
最后,您可能认为ConsoleService
包装器所以很薄,其实现确实需要任何单元/功能测试。 ConsoleService
的实施可能对您的应用程序至关重要,因为任何缺陷都将通过集成测试或UAT中的应用程序的手动检查来公开。
你最终会得到类似的东西(道歉,我不会说Scala所以它是Java):
public class RealConsoleService implements ConsoleService {
private final java.io.Console delegate;
public RealConsoleService(java.io.Console delegate) {
this.delegate = delegate;
}
@Override
public String readLine() throws IOError {
return delegate.readLine();
}
}
两个有趣的观点:
ConsoleService
重命名为更抽象的ApplicationInputOutputService
并插入不同的实现。