【问题标题】:how can we simulate Ctrl+C to stop the console app from waiting for user input in java我们如何模拟 Ctrl+C 来阻止控制台应用程序在 java 中等待用户输入
【发布时间】:2017-10-17 05:47:19
【问题描述】:

我正在尝试测试一个在每一步后等待用户输入的命令行应用程序。我可以使用 Stefan Birkner 提供的 System Rules 测试应用程序。目前,我提供从头到尾的输入,这就像一个魅力,我可以断言来自系统日志的最终输出。

但是,我想在应用程序结束之前测试否定情况,我在开始时提供无效输入以评估错误消息。当给出无效输入时,控制台会打印一条错误消息并一直等待用户提供有效输入。如何发送 Ctrl+C 使用如下所示:

systemInMock.provideLines(Ctrl+C);

systemInMock.provideLines 只接受字符串。有没有办法发送 Ctrl+C 信号?

我的 junit 测试示例如下所示:

@Test
public void testInValidMarker() throws Exception{
    systemInMock.provideLines("abc","def","1");
    Main.main(new String[]{});
    assertTrue(systemOutRule.getLog().contains("Invalid marker, try again"));
}

感谢您的帮助!

【问题讨论】:

  • 当您使用 CTRL-C 时操作系统会做什么取决于主机环境。您能告诉我们您使用的是什么操作系统吗?

标签: java


【解决方案1】:

如果我没记错的话,当你执行 ctrl+c 时,它实际上并没有被写入控制台。如果这是真的,那么在任何情况下你的程序都不会被赋予 ctrl+c,所以provideLines 永远不会处于赋予它的位置 ctrl+c

为了证明,打开 cmd 并输入带有程序参数的程序(在我的例子中,我使用 ant)。如果您键入ant,然后键入ctrl+c,则光标将移至新行。

有两种方法可以控制终止行为:

  1. 您可以使用 shutdown hook (从这个previously asked question 找到)。这样做可以让您处理发生的事情(可能存在问题)。
  2. 或者您可以创建自己的终止参数,如-qq,这将触发结束程序的操作(可能是System.exit(1))。这样您就可以模拟该输入。

【讨论】:

    【解决方案2】:

    在 UNIX/Linux 中,当你输入 CTRL-C 时,你的 shell 会拦截它并向进程发送一个 SIGINT 信号 -- 参见:How does Ctrl-C terminate a child process?

    因此,系统规则项目对您没有任何帮助 - 在这种情况下,进程不会收到任何字符输入。

    默认情况下,整个 JVM 在收到SIGINT 时会关闭。这对于正在运行的测试来说显然是个坏消息。

    SO 问题Signal handling using "TERM" -- 可能有用。

    Java 可移植性的一个副作用是,对于某些操作系统功能,它要么将事物抽象到无法识别,要么根本不公开它们。

    我怀疑您的要求无法实现。

    如果允许您稍微更改要求,您可以要求用户使用CTRL-D 关闭——这会使用EOF 关闭标准输入。

    虽然这有点矫枉过正,但您可以使用ProcessBuilder 启动一个全新的JVM 来运行您的程序。您可能会想象您将获得一个 API 来向该进程发送任意信号。但出于可移植性的原因,你所能做的就是process.destroy(),它发送SIGTERM

    【讨论】:

      【解决方案3】:

      尝试将此作为评论,但它没有正确阅读。不过,这并不完全是“答案”。

      所以 Java 在控制台输入方面真的很糟糕。它一次读取一整行,而您对此无能为力——在用户点击返回之前,无法捕获特殊字符,甚至无法查看任何输入。此外,我认为 ctrl-d 会关闭您的输入会话——(如果您在此处不使用任何其他建议,请将该测试添加到您的用例中,因为它会使您进入您没想到的状态!)

      三个建议:

      最简单的:如果您可以使用 GUI 并且不是真的在寻找正在进行的输入/响应 REPL,最简单的答案通常是使用 JOptionPane 来弹出一个快速对话框。这是一种获取用户输入的单线解决方案,但对于正在进行的命令驱动系统来说不是很好。

      如果您不能使用 swing(如果您正在运行 headless),那么您可能别无选择,但您可以使用 JLine 库。这会给你更多的灵活性。这就是 Groovysh 的 REPL 方式。它可以让您在输入时查看每个字符,并执行诸如完成之类的操作,用户可以输入文件名的一部分并点击选项卡,然后您将其余部分输入给他。

      如果您不想使用 JLine 但想要一种 REPL 感觉,还有一个更复杂的 GUI 解决方案——创建一个摆动控制台窗口。一个简单的解决方案只是一个允许输入的文本输入框和一个显示结果的文本区域,但肯定有一些库提供更完整的控制台解决方案。

      这里的重点是,单独使用 Java 标准输入对于除了琐碎/个人脚本之外的任何事情都不是一个好的解决方案——即使那样我也会避免它。也许不是您要求的答案,但也许是您需要的答案:)

      【讨论】:

        猜你喜欢
        • 2023-03-21
        • 2011-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多