Вопрос-ответ

JUnit test for System.out.println()

Тест JUnit для System.out.println()

Мне нужно написать JUnit-тесты для старого приложения, которое плохо спроектировано и выдает много сообщений об ошибках в стандартный вывод. Когда getResponse(String request) метод работает правильно, он возвращает XML-ответ:

@BeforeClass
public static void setUpClass() throws Exception {
Properties queries = loadPropertiesFile("requests.properties");
Properties responses = loadPropertiesFile("responses.properties");
instance = new ResponseGenerator(queries, responses);
}

@Test
public void testGetResponse() {
String request = "<some>request</some>";
String expResult = "<some>response</some>";
String result = instance.getResponse(request);
assertEquals(expResult, result);
}

Но когда он получает неверно сформированный XML или не понимает запрос, он возвращает null и записывает некоторые данные в стандартный вывод.

Есть ли какой-либо способ подтвердить вывод консоли в JUnit? Чтобы отслеживать такие случаи, как:

System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
Переведено автоматически
Ответ 1

использовать ByteArrayOutputStream и System.setXXX просто:

private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
private final PrintStream originalErr = System.err;

@Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}

@After
public void restoreStreams() {
System.setOut(originalOut);
System.setErr(originalErr);
}

примеры тестов:

@Test
public void out() {
System.out.print("hello");
assertEquals("hello", outContent.toString());
}

@Test
public void err() {
System.err.print("hello again");
assertEquals("hello again", errContent.toString());
}

Я использовал этот код для тестирования опции командной строки (утверждая, что -version выводит строку version и т.д. и т.п.)

Редактировать: Предыдущие версии этого ответа вызывались System.setOut(null) после тестов; Это причина NullPointerExceptions, на которые ссылаются комментаторы.

Ответ 2

Я знаю, что это старый поток, но для этого есть хорошая библиотека: Системные правила
Пример из документации:

public void MyTest {
@Rule
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();

@Test
public void overrideProperty() {
System.out.print("hello world");
assertEquals("hello world", systemOutRule.getLog());
}
}

Это также позволит вам перехватывать System.exit(-1) и другие вещи, для которых потребуется протестировать инструмент командной строки.

Ответ 3

Вместо перенаправления System.out я бы реорганизовал класс, который использует System.out.println(), передав PrintStream в качестве соавтора, а затем используя System.out в производстве и тестовый шпион в тесте. То есть используйте внедрение зависимостей, чтобы исключить прямое использование стандартного выходного потока.

В производстве

ConsoleWriter writer = new ConsoleWriter(System.out));

В тесте

ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));
writer.printSomething();
assertThat(outSpy.toString(), is("expected output"));

Обсуждение

Таким образом, тестируемый класс становится тестируемым с помощью простого рефакторинга, без необходимости косвенного перенаправления стандартного вывода или скрытого перехвата системным правилом.

Ответ 4

Вы можете настроить поток печати System.out с помощью setOut() (и для in и err). Можете ли вы перенаправить это в поток печати, который записывает в строку, а затем проверить это? Это, казалось бы, самый простой механизм.

(Я бы посоветовал на каком-то этапе преобразовать приложение в какую-нибудь платформу ведения журнала - но я подозреваю, что вы уже знаете об этом!)

2023-11-29 14:24 java junit