2016-03-06 46 views
1

我正在开发一个简化控制台应用程序创建的框架。我的框架是用Scala编写的,我正在使用ScalaTest和Mockito进行单元测试。如何模拟,或以其他方式测试readPassword?

我需要能够模拟java.io.Console,但它被宣布是最终的。我试图达到100%的单元测试覆盖率,目前这是唯一阻止我的功能和单元测试。

到目前为止,我还没有能够得到任何解决方案很远,我只是想不到这样做的一种方式。它没有实现一个我可以模拟的接口,这个方法在其他地方是不可用的,显然我不能扩展它。我想也许有一种解决方案,可能涉及某种动态方法调用方法,如readLinereadPassword,但我没有足够的经验去获得任何地方的这种思路!

+2

100%的覆盖率是在CS,亚伯拉罕林肯最大的幻想:) –

+0

你有没有考虑过查看SystemRules(http://stefanbirkner.github.io/system-rules/index.html),它的一套junit处理System类的规则。它可能会给你一些启发。或者,ScalaCheck可以在这种情况下提供一些帮助,它是一种不同的测试方法。 – Gavin

+0

@SleimanJneidi我毫不怀疑你在那里是正确的! :)知道这是否有解决方案仍然很有趣,它似乎是Java中API设计的一个疏忽,我还没有遇到过这样的事情。 – Seer

回答

0

您应该创建自己的界面来包装与java.io.Console的所有交互,例如,

public interface ConsoleService { 
    ... 
} 

只要你只通过的ConsoleService实例的控制台交互,那么你就可以嘲笑你的代码的ConsoleService和测试99%,你通常会。接口将成为应用程序的边界,用于整个应用程序的功能测试以及直接与其交互的类的单元测试。

现在我们已经将问题的范围缩小为“如何测试ConsoleService实施”,我们需要获得一点创意。例如,您可以将控制台输出重定向到一个文件并检查该文件的内容。您可能甚至不想测试Scala中的ConsoleService;您可以使用ConsoleService编写一个框架应用程序,然后使用您选择的脚本语言在您最喜欢的操作系统上启动一个真正的控制台,与您的骨架应用程序进行交互并以此方式测试ConsoleService。你可以得到像你这样的创意(和哈克),因为:

  1. 它只影响少量的测试;和
  2. 你的应用程序很可能会成熟到一个点,其中ConsoleService实现不需要改变很多,即你的古怪测试解决方案将不会成为未来开发人员的重大负担。

由于这些原因,应该是显而易见的,这是一个好主意,让ConsoleService包装非常薄,因为没有任何逻辑将通过奇怪ConsoleService测试进行测试,而不是漂亮的友好斯卡拉测试。通常直接授权到java.io.Console方法已经足够好了,但您应该允许应用程序的功能测试来驱动接口而不是做出任何推定(您的功能测试断言可能依赖于与模拟ConsoleService的特定交互,或者可能取决于状态的一个存根,您可以在测试中控制的ConsoleService的测试实现)。

最后,你可能会认为ConsoleService包装是,所以很薄,它的实现确实需要任何单元/功能测试。 ConsoleService的实现可能对您的应用程序非常关键,以至于UAT中的应用程序的集成测试或手动检查将暴露任何缺陷。

也许最终你会像这样的东西(抱歉,我不说话斯卡拉所以它的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并插入不同的实现。
  • 相同的概念可用于测试使用其他难以测试的API的应用程序。许多Java有用的文件IO方法都是静态方法,因此很难在测试中进行控制。通过如上所述的界面包装,您的应用程序功能变得易于测试。
相关问题