Написание модульных тестов является неотъемлемой частью разработки программного обеспечения. Одна проблема, которую вы должны решить, когда тестируемый класс взаимодействует с операционной системой, — это моделировать ее поведение. Это можно сделать с помощью имитаций вместо реальных объектов, предоставляемых Java Runtime Environment (JRE). Библиотеки, которые поддерживают mocking для Java, являются, например, mockito или jMock .
Насмешка над объектами — это замечательно, когда вы полностью контролируете их создание. При работе со стандартным вводом и стандартным выводом это немного сложно, но не невозможно, так как java.lang.System
позволяет заменить стандартные InputStream
и OutputStream
.
1
2
|
System.setIn(in); System.setOut(out); |
Чтобы вам не приходилось заменять потоки до и после каждого теста вручную, вы можете использовать org.junit.rules.ExternalResource
. Этот класс предоставляет два метода before()
и after()
, которые вызываются, как и предполагают их имена, до и после каждого теста. Таким образом, вы можете легко настроить и очистить ресурсы, необходимые для всех ваших тестов в рамках одного класса. Или, чтобы вернуться к исходной проблеме, замените поток ввода и вывода для java.lang.System
.
Именно то, что я описал выше, реализуется библиотекой system-rules . Чтобы увидеть, как это работает, давайте начнем с простого примера:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class CliExample { private Scanner scanner = new Scanner(System.in, "UTF-8" ); public static void main(String[] args) { CliExample cliExample = new CliExample(); cliExample.run(); } private void run() { try { int a = readInNumber(); int b = readInNumber(); int sum = a + b; System.out.println(sum); } catch (InputMismatchException e) { System.err.println( "The input is not a valid integer." ); } catch (IOException e) { System.err.println( "An input/output error occurred: " + e.getMessage()); } } private int readInNumber() throws IOException { System.out.println( "Please enter a number:" ); String nextInput = scanner.next(); try { return Integer.valueOf(nextInput); } catch (Exception e) { throw new InputMismatchException(); } } } |
Приведенный выше код считывает два промежуточных значения из стандартного ввода и выводит их сумму. Если пользователь вводит неверные данные, программа должна вывести соответствующее сообщение в поток ошибок.
В первом тестовом примере мы хотим убедиться, что программа правильно суммирует два числа и выводит результат:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public class CliExampleTest { @Rule public final StandardErrorStreamLog stdErrLog = new StandardErrorStreamLog(); @Rule public final StandardOutputStreamLog stdOutLog = new StandardOutputStreamLog(); @Rule public final TextFromStandardInputStream systemInMock = emptyStandardInputStream(); @Test public void testSuccessfulExecution() { systemInMock.provideText( "2\n3\n" ); CliExample.main( new String[]{}); assertThat(stdOutLog.getLog(), is( "Please enter a number:\r\nPlease enter a number:\r\n5\r\n" )); } ... } |
Для моделирования System.in
мы используем системные правила TextFromStandardInputStream
. Переменная экземпляра инициализируется с пустым входным потоком путем вызова emptyStandardInputStream()
. В самом тестовом примере мы предоставляем intput для приложения, вызывая provideText()
с новой provideText()
в соответствующих точках. Затем мы вызываем метод main()
нашего приложения. Наконец, мы должны утверждать, что приложение записало два оператора ввода и результат в стандартный ввод. Последнее делается через экземпляр StandardOutputStreamLog
. getLog()
его метод getLog()
мы извлекаем все, что было записано в стандартный вывод во время текущего теста.
StandardErrorStreamLog
может использоваться одинаково для проверки того, что было написано для стандартной ошибки:
1
2
3
4
5
6
|
@Test public void testInvalidInput() throws IOException { systemInMock.provideText( "a\n" ); CliExample.main( new String[]{}); assertThat(stdErrLog.getLog(), is( "The input is not a valid integer.\r\n" )); } |
Помимо этого system-rules
также предлагает правила для работы с System.getProperty()
, System.setProperty()
, System.exit()
и System.getSecurityManager()
.
Вывод : С тестированием системных правил приложения командной строки с модульными тестами становятся еще проще, чем использование самих правил junit. Весь стандартный код для обновления системной среды до и после каждого контрольного примера входит в ряд простых в использовании правил.
PS: Вы можете найти полные источники здесь .
Ссылка: | Тестирование System.in и System.out с помощью системных правил от нашего партнера по JCG Мартина Моиса в блоге Martin’s Developer World . |