Java, Junit - Захват стандартного ввода/вывода для использования в unit test
Я пишу интеграционные тесты с помощью JUnit для автоматизации тестирования консольного приложения. Приложение является домашним заданием, но эта часть не является домашней работой. Я хочу, чтобы эти тесты были более эффективными - я не хочу возвращаться и проверять уже проверенные части приложения. (Стандартные причины использования модульных тестов)
Во всяком случае, я не могу найти статью или найти статью о захвате вывода, чтобы я мог сделать assertEquals
на ней, и не предоставлял автоматический ввод. Меня не волнует, идет ли выход/вход в панель консоли/вывода. Мне нужно только выполнить тест и проверить вывод, что ожидается с учетом ввода.
У кого-нибудь есть статья или код, чтобы помочь с этим.
Ответы
Ответ 1
Используйте System.setOut() (и System.setErr()
) для перенаправления вывода на произвольный поток печати - который может быть таким, который вы читаете от программного.
Например:
final ByteArrayOutputStream myOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(myOut));
// test stuff here...
final String standardOutput = myOut.toString();
Ответ 2
Класс System
имеет методы setIn()
, setOut()
и setErr()
, которые позволяют вам устанавливать стандартные потоки ввода, вывода и ошибок, например. до ByteArrayOutputStream
, который вы можете проверить по своему усмотрению.
Ответ 3
Вот решение вместо ByteArrayOutputStream. Это ничего не добавляет к идее System.setOut. Скорее, я хочу поделиться реализацией, которая лучше, чем захват всего в ByteArrayOutputStream. Я предпочитаю захватывать только выбранную информацию и позволять всем сообщениям журналов появляться в консоли, поскольку они регистрируются, а не захватывают все в balckbox (размера которого?) Для последующей обработки.
/**
* Once started, std output is redirected to this thread.
* Thread redirects all data to the former system.out and
* captures some strings.*/
static abstract class OutputCaputre extends Thread {
// overrdie these methods for System.err
PrintStream getDownstream() { return System.out;}
void restoreDownstream() { System.setOut(downstream);}
// will be called for every line in the log
protected abstract void userFilter(String line);
final PrintStream downstream;
public final PipedInputStream pis;
private final PipedOutputStream pos;
OutputCaputre() throws IOException {
downstream = getDownstream();
pos = new PipedOutputStream();
pis = new PipedInputStream(pos);
System.setOut(new PrintStream(pos));
start();
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(pis));
// once output is resotred, we must terminate
while (true) {
String line = br.readLine();
if (line == null) {
return;
}
downstream.println(line);
userFilter(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void terminate() throws InterruptedException, IOException {
restoreDownstream(); // switch back to std
pos.close(); // there will be no more data - signal that
join(); // and wait until capture completes
}
};
Вот пример использования класса:
OutputCaputre outputCapture = new OutputCaputre() {
protected void userFilter(String line) {
downstream.println("Capture: " + line);
}
};
System.out.println("do you see me captured?");
// here is your test
outputCapture.terminate(); // finally, stop capturing