【问题标题】:how to mock calling kotlin.system.exitProcess如何模拟调用 kotlin.system.exitProcess
【发布时间】:2019-05-19 17:33:03
【问题描述】:

我想测试一些使用调用kotlin.system.exitProcess()的第三方代码的代码,在标准库中定义如下:

@kotlin.internal.InlineOnly
public inline fun exitProcess(status: Int): Nothing {
    System.exit(status)
    throw RuntimeException("System.exit returned normally, while it was supposed to halt JVM.")
}

当调用exitProcess() 时,JVM 会停止并且无法进行进一步的测试。我没有设法用 mockk 模拟对exitProcess() 的调用。有可能吗?

一些进一步的信息:

第 3 方库是 Clikt (https://ajalt.github.io/clikt/),这是一个用于构建命令行界面的好库。 Clikt 应用程序解析命令行,如果失败则退出。这可能是调用 System.exit 可以的罕见原因之一。当然还有更多可测试的解决方案,但无论如何,当使用 3rd 方库时,争论在 库中可以更好地完成什么已经过时了。

我真正想要测试的是,我的应用程序在使用 --help 或错误参数调用时会写入预期的使用消息。

我还尝试以这种方式模拟对System.exit() 的调用: mockkStatic("java.lang.System") 每个 { System.exit(any()) }.throws(RuntimeException("blubb")) 这导致了另一个问题,所有对 System 的调用都被模拟了:

io.mockk.MockKException: every/verify {} block were run several times. Recorded calls count differ between runs
Round 1: class java.lang.System.getProperty(kotlin.ignore.old.metadata), class java.lang.System.exit(-630127373)
Round 2: class java.lang.System.exit(158522875)

有趣的是,我设法使用 jmockit 在 Java 中进行了测试,如下所示:

public class MainTestJ {
    private ByteArrayOutputStream consoleOut;

    @BeforeEach
    public void mockConsole() {
        consoleOut = new ByteArrayOutputStream();
        System.setOut(new PrintStream(consoleOut));
    }

    @Test
    public void can_mock_exit() {
        new MockUp<System>() {
            @Mock
            public void exit(int exitCode) {
                System.out.println("exit called");
            }
        };
        assertThatThrownBy(() -> {
            new Main().main(new String[] { "--help" });
        }).isInstanceOf(RuntimeException.class);
        assertThat(consoleOut.toString()).startsWith("Usage: bla bla ...");
    }
}

【问题讨论】:

  • 我会重新考虑您正在使用的第 3 方代码。要么它不打算用作库,所以无论如何使用它都是错误的,或者它只是废话,因为没有库应该永远终止进程,他们应该让用户代码做出决定..
  • @GiacomoAlzetta 我同意 3rd 方库,它绝对不应该那样做。但是这个问题很有趣。
  • @tchick 你能发布你对函数存根的尝试吗?
  • 如果第三方代码/库是公开的,请分享它的名称。还有一些调用某事的代码,调用exit。那么怎么做就更清楚了。
  • 我编辑了帖子以提供有关第 3 方库、测试设置和更多实验的更多信息。

标签: kotlin mockk


【解决方案1】:

我玩了一段时间试图让它工作,但不幸的是这是不可能的。模拟这个函数有几个困难;它是一个顶级函数并且它返回Nothing。这些中的每一个都可以克服,但是使之成为不可能的是函数是内联。内联的 kotlin 函数不会在字节码中生成方法,正如它在锡上所说的那样,内联。问题是 Mockk 和其他模拟库在模拟时使用字节码指令。有关详细信息,请参阅此issue

您最好的选择是根本不尝试模拟此函数,而是模拟对您正在使用的第三方库的调用。毕竟,您不应该测试这个第三方代码,而应该只测试您自己的代码。更好的是,也许你应该寻找一个替代图书馆。正如 cmets 中已经说明的那样,第三方库不应该退出进程,这应该留给客户端代码。

【讨论】:

    猜你喜欢
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 2019-12-08
    相关资源
    最近更新 更多