Java I / O - 模拟System.console()的输入

时间:2015-04-03 11:52:38

标签: java junit java-io

我正在为练习中创建的程序编写JUnit。这意味着测试需要涵盖尽可能多的案例,而且我对计划中某些事情的实施方式没有任何影响。此外,程序运行无限循环,在某一点上,它需要用户输入一些东西 对于JUnit测试,我在另一个Thread中运行该程序,并在JUnit Thread内模拟用户输入。

到目前为止,如果程序从System.in读取用户输入,一切正常,因为此流可以轻松替换。但是,程序与System.console()交互的可能性目前无法通过我的测试进行覆盖。

是否有可能模拟System.console()的输入,例如通过用另一个流替换其输入源?

(注意:JUnit测试必须使用没有任何外部库的Java 6(JUnit和Hamcrest除外)。)

编辑:不幸的是,我无法更改要测试的程序类。

3 个答案:

答案 0 :(得分:4)

在查看JDK源代码后,我发现Console类正在从标准输入(System.in)读取数据:

reader = new LineReader(StreamDecoder.forInputStreamReader(new FileInputStream(FileDescriptor.in), readLock, cs));

其中FileDescriptor.in是指向实际标准输入(public static final FileDescriptor in = standardStream(0);)的常量。 因此,即使使用System.in替换System.setIn(),控制台类仍将使用真正的标准输入。

您唯一的选择是使用模拟替换Console对象。

答案 1 :(得分:3)

我认为您需要按照this post中的说明为控制台创建抽象。并在代码中使用此抽象而不是System.console()。然后你可以在测试中模拟控制的抽象。

编辑: 另一个更复杂的解决方案是在JVM中加载System.console()(或sun底层类)时修改字节代码。这是通过提供您自己的ClassLoader实现来完成的,您可以找到有关如何执行此操作的信息。 我不确定你想要这个兔子洞......

答案 2 :(得分:0)

在途中,我可以想到使用模拟扫描仪类。例如

     int i = sc.nextInt(); 

现在将调用模拟实现

 public void Scanner getScanner(){

   }


  // inject mock object for unit testing and in prod ,
      real object with input   stream from console
   public void Scanner setScanner(Scanner scanner){

    }