【问题标题】:Java I/O - Simulate input for System.console()Java I/O - 模拟 System.console() 的输入
【发布时间】:2015-06-08 12:21:03
【问题描述】:

我正在为练习中创建的程序编写 JUnit。这意味着测试需要覆盖尽可能多的情况,我对程序中某些事情的实现方式没有任何影响。此外,该程序运行一个无限循环,在某一时刻,它需要用户输入一些内容。
对于 JUnit 测试,我在另一个 Thread 中运行程序,并在 JUnit Thread 中模拟用户输入。

到目前为止,如果程序从System.in 读取用户输入,一切正常,因为这个流很容易被替换。但也有可能程序与System.console() 交互,目前我的测试无法涵盖。

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

(注意:JUnit 测试必须使用 Java 6,而不需要任何外部库(JUnit 和 Hamcrest 除外)。)

编辑:很遗憾,我无法更改要测试的程序的类。

【问题讨论】:

  • 你的类的构造函数必须接受一个Console 对象,所以你可以注入它。然后在测试中你必须构造一个Consolemock 实例,你必须将它传递给构造函数。
  • @SvetlinZarev 看到我的编辑。没有别的办法吗?

标签: java junit java-io


【解决方案1】:

我认为您需要为控制台创建一个抽象,如this post 中所述。并在代码中使用这个抽象来代替System.console()。然后你可以在测试中模拟抽象的you控件。

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

【讨论】:

  • 由于我无法影响实际程序用作控制台的内容,因此抽象将无用,因为程序仍将使用 System.console() 而不是我的自定义控制台。如果您可以更改使用的控制台,这将是不同的,就像 System.in 使用 System.setIn() 可能的那样
【解决方案2】:

在路上我可以想到使用模拟扫描仪类。例如

     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){

    }

【讨论】:

  • 他问的是Console而不是Scanner
  • 但基本上他也想从扫描仪中读取流
  • 我不想阅读流。我想模拟输入并因此操纵System.console()输入源
【解决方案3】:

查看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.setIn() 替换System.in,控制台类仍将使用真正的标准输入。

您唯一的选择是将Console 对象替换为mock

【讨论】:

    猜你喜欢
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    • 1970-01-01
    • 2011-05-02
    • 2011-12-15
    • 1970-01-01
    • 2021-11-25
    相关资源
    最近更新 更多