У меня есть несколько методов, которые должны вызывать System.exit()
определенные входы. К сожалению, тестирование этих случаев приводит к прекращению работы JUnit! Помещение вызовов методов в новый System.exit()
поток, похоже, не помогает, поскольку завершает JVM, а не только текущий поток. Существуют ли какие-либо общие схемы для решения этой проблемы? Например, могу ли я заменить заглушку System.exit()
?
[EDIT] Данный класс на самом деле является инструментом командной строки, который я пытаюсь протестировать внутри JUnit. Может быть, JUnit просто не подходит для работы? Приветствуются предложения по дополнительным инструментам регрессионного тестирования (желательно те, которые хорошо интегрируются с JUnit и EclEmma).
java
multithreading
unit-testing
junit
testability
Крис Конвей
источник
источник
System.exit()
плохо - ваша программа должна быстро провалиться. Создание исключения просто продлевает приложение в недопустимом состоянии в ситуациях, когда разработчик хочет выйти и выдает ложные ошибки.Ответы:
Действительно, Derkeiler.com предлагает:
System.exit()
?System.exit()
на выход из JVM:Обновление декабря 2012 года:
Уилл предлагает в комментариях с помощью правил системы , коллекция JUnit (4.9+) правила для тестирования кода , который использует
java.lang.System
.Это было первоначально упомянуто Стефаном Биркнером в его ответе в декабре 2011 года.
Например:
источник
System.exit
всякий раз, когда предоставляется неверный аргумент командной строки.В библиотеке System Lambda есть метод. С помощью
catchSystemExit
этого правила вы можете тестировать код, который вызывает System.exit (...):Для Java 5-7 в Системных правилах библиотеки есть правило JUnit, которое называется ExpectedSystemExit. С помощью этого правила вы можете тестировать код, который вызывает System.exit (...):
Полное раскрытие: я автор обеих библиотек.
источник
ExpectedSystemRule
, конечно, приятно; проблема в том, что она требует дополнительной сторонней библиотеки, которая предоставляет очень мало с точки зрения реальной полезности, и является специфичной для JUnit.exit.checkAssertionAfterwards()
.Как насчет введения «ExitManager» в эти методы:
Рабочий код использует ExitManagerImpl, а тестовый код использует ExitManagerMock и может проверить, был ли вызван метод exit () и с каким кодом выхода.
источник
Вы на самом деле можете смоделировать или заглушить
System.exit
метод в тесте JUnit.Например, используя JMockit, вы можете написать (есть и другие способы):
РЕДАКТИРОВАТЬ: Альтернативный тест (с использованием новейшего API JMockit), который не позволяет запускать какой-либо код после вызова
System.exit(n)
:источник
exit
вызова (не то, чтобы это действительно было проблемой, IMO).Runtime
может быть поддельным , но не останавливается,System.exit
по крайней мере, в моем сценарии запуска тестов в Gradle.Один из приемов, который мы использовали в нашей кодовой базе, заключался в инкапсуляции вызова System.exit () в Runnable impl, который рассматриваемый метод использовал по умолчанию. Для модульного тестирования мы установили другую макет Runnable. Что-то вроде этого:
... и метод тестирования JUnit ...
источник
Создайте фиктивный класс, который обёртывает System.exit ()
Я согласен с EricSchaefer . Но если вы используете хороший Mocking Framework, такой как Mockito, достаточно простого конкретного класса, нет необходимости в интерфейсе и двух реализациях.
Остановка выполнения теста в System.exit ()
Проблема:
Дразнящий
Sytem.exit()
не прекратит выполнение. Это плохо, если вы хотите проверить, чтоthing2
не выполняется.Решение:
Вы должны рефакторинг этого кода в соответствии с предложением Мартина :
И сделать
System.exit(status)
в вызывающей функции. Это заставляет вас иметь все своиSystem.exit()
в одном месте или рядомmain()
. Это чище, чем звонитьSystem.exit()
глубоко внутри вашей логики.Код
Упаковочный:
Основной:
Тест:
источник
Мне нравятся некоторые ответы, которые уже даны, но я хотел продемонстрировать другую технику, которая часто полезна при тестировании устаревшего кода. Данный код вроде:
Вы можете выполнить безопасный рефакторинг, чтобы создать метод, обертывающий вызов System.exit:
Затем вы можете создать подделку для вашего теста, которая переопределяет выход:
Это общая методика замены поведения для тестовых случаев, и я использую ее все время при рефакторинге унаследованного кода. Обычно это не то, что я собираюсь оставить, а промежуточный шаг, чтобы протестировать существующий код.
источник
Беглый взгляд на API показывает, что System.exit может выдать исключение ESP. если менеджер безопасности запрещает отключение виртуальной машины. Может быть, решение будет установить такой менеджер.
источник
Вы можете использовать java SecurityManager, чтобы запретить текущему потоку завершать работу Java VM. Следующий код должен делать то, что вы хотите:
источник
Чтобы ответ VonC работал на JUnit 4, я изменил код следующим образом
источник
Вы можете протестировать System.exit (..) с заменой экземпляра среды выполнения. Например, с TestNG + Mockito:
источник
Существуют среды, в которых возвращаемый код завершения используется вызывающей программой (например, ERRORLEVEL в MS Batch). У нас есть тесты по основным методам, которые делают это в нашем коде, и наш подход заключается в использовании аналогичного переопределения SecurityManager, как и в других тестах здесь.
Вчера вечером я собрал небольшой JAR-файл, используя аннотации Junit @Rule, чтобы скрыть код менеджера безопасности, а также добавить ожидания, основанные на ожидаемом коде возврата. http://code.google.com/p/junitsystemrules/
источник
Большинство решений будет
System.exit()
вызоваSecurityManager
Таким образом, большинство решений не подходят для ситуаций, когда:
System.exit()
assertAll()
, например, с.Я не был доволен ограничениями, наложенными существующими решениями, представленными в других ответах, и поэтому придумал что-то самостоятельно.
Следующий класс предоставляет метод,
assertExits(int expectedStatus, Executable executable)
который утверждает, чтоSystem.exit()
вызывается с указаннымstatus
значением, и тест может продолжаться после него. Он работает так же, как JUnit 5assertThrows
. Это также уважает существующего менеджера по безопасности.Осталась одна проблема: когда тестируемый код устанавливает новый менеджер безопасности, который полностью заменяет менеджер безопасности, установленный тестом. Все остальные
SecurityManager
известные мне решения имеют ту же проблему.Вы можете использовать класс следующим образом:
Код может быть легко перенесен в JUnit 4, TestNG или любую другую инфраструктуру, если это необходимо. Единственный элемент, специфичный для фреймворка, не проходит тест. Это может быть легко изменено на что-то не зависящее от фреймворка (кроме Junit 4
Rule
Есть возможности для улучшения, например, перегрузка
assertExits()
настраиваемыми сообщениями.источник
Используйте
Runtime.exec(String command)
для запуска JVM в отдельном процессе.источник
Существует небольшая проблема с
SecurityManager
решением. Некоторые методы, такие какJFrame.exitOnClose
, также вызываютSecurityManager.checkExit
. В моем приложении я не хотел, чтобы этот вызов потерпел неудачу, поэтому я использовалисточник
Вызов System.exit () является плохой практикой, если только он не выполняется внутри main (). Эти методы должны вызывать исключение, которое, в конечном счете, перехватывается вашим main (), который затем вызывает System.exit с соответствующим кодом.
источник