Как издеваться над вызовом kotlin.system.exitProcess
Я хочу протестировать некоторый код, который использует сторонний код, который вызывает kotlin.system.exitProcess()
определяется следующим образом в стандартной библиотеке lib:
@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 останавливается и дальнейшее тестирование невозможно. Мне не удалось высмеять звонки exitProcess()
с макетом. Является ли это возможным?
Некоторая дополнительная информация:
Сторонней библиотекой является Clikt ( https://ajalt.github.io/clikt/), отличная библиотека для создания интерфейса командной строки. Приложение Clikt анализирует командную строку и завершает работу в случае сбоя. Это может быть одной из редких причин, когда вызывается System.exit. Конечно, есть более тестируемые решения, но в любом случае, при работе со сторонними библиотеками, спорить о том, что может быть лучше сделано в lib, устарело.
На самом деле я хочу проверить, что мое приложение записывает ожидаемое сообщение об использовании при вызове с --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)
Как ни странно, мне удалось проверить это на Java с помощью jmockit, например так:
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 ...");
}
}
1 ответ
Я играл с этим некоторое время, пытаясь заставить его работать, но, к сожалению, это невозможно. Есть несколько трудностей с насмешкой над этой функцией; что это функция верхнего уровня и что она возвращает Nothing
, Каждый из них может быть преодолен, но что делает невозможным то, что функция встроена. Встроенные функции kotlin не производят методы в байт-коде, это, как сказано в олове, встроено. Проблема в том, что Mockk и другие библиотеки-насмешки используют инструкции для байт-кода. Обратитесь к этой проблеме для получения дополнительной информации.
Ваша лучшая альтернатива - вообще не пытаться имитировать эту функцию, а вместо этого смоделировать вызов в сторонней библиотеке, которую вы используете. В конце концов, вы не должны тестировать этот сторонний код, только свой собственный код. А еще лучше, может быть, вам следует искать альтернативную библиотеку. Как уже было сказано в комментариях, сторонняя библиотека не должна выходить из процесса, это следует оставить на усмотрение клиентского кода.