Интересное поведение при моделировании ввода пользовательской консоли при тестировании многопоточного Java-приложения с Junit - PullRequest
1 голос
/ 28 марта 2019

Я пытаюсь разработать сценарий автоматической оценки назначения с использованием JUnit в Java. Я имитирую пользовательский ввод, передавая входные данные тестового примера (считанные из файла в classpath), меняя System.in на ByteArrayInputStream, содержащий строковые данные в байтах. Я хочу иметь возможность запускать несколько тестовых случаев, чтобы проверить все случаи, а затем использовать построенный Gradle отчет, чтобы отметить отправку назначения.

В настоящее время мне удалось смоделировать пользовательский ввод, чтобы отразить ввод данных, предоставленных тестовыми примерами, используя эту ссылку: JUnit: Как смоделировать тестирование System.in? . Я также изменяю System.out на PrintStream для захвата напечатанных операторов из назначения. Мой основной метод порождает новый поток, внутри которого выполняются коды назначения, как показано ниже.

Модульные тесты успешно выполняются, когда я тестирую каждый аннотированный @Test случай отдельно. Однако, когда я запускаю все тесты, содержащиеся в одном классе Test, JUnit успешно работает в первом случае с аннотацией @Test, но терпит неудачу с возможными, что здесь несколько неожиданно. Надеемся, что приведенные ниже коды помогут прояснить ситуацию.

Мой метод Main :

public static void main(String ... args) {
    Assignment assignment = new Assignment();
    new Thread(assignment).start();
}

В моем тестовом классе есть несколько аннотированных методов @before и @after:

@Before
public void setup() {
    systemIn = System.in; // global variable
    systemOut = System.out; // global variable
    output = new ByteArrayOutputStream(); // global variable
    System.setOut(new PrintStream(output));
    assignment = new Assignment();
}
@After
public void conclude() {
    System.setIn(systemIn);
    System.setOut(systemOut);
}

Я читаю соответствующий файл для каждого ввода и вывода тестового примера, а в приведенной ниже функции я устанавливаю ввод тестового набора.

private void setInput(String data) {
    ByteArrayInputStream input = new ByteArrayInputStream(data.getBytes());
    System.setIn(input);
}

Я выполняю каждый тестовый пример следующим образом:

@org.junit.Test // 2,3,4 ....for other cases
public void runTestCase1() { 
    testCases(1);
}

Класс IO , который использует присвоение, выглядит следующим образом:

public static String readLine() { // w/o try/catch blocks
    String read = reader.readLine(); // reader -> bufferedReader(new InputStream(System.in))
    return read.trim();
}

Также обратите внимание, что я использую Thread.sleep(50) перед вызовом основного метода, чтобы входной тестовый пример был успешно прочитан и загружен в System.in во время выполнения Назначения.

При запуске всех тестов вместе, первый тест дает правильный результат, то есть совпадают ожидаемый и фактический выходы. Однако для второго случая и далее IO.readline() генерирует исключение нулевого указателя , и, следовательно, присвоение не приводит к выводу. После расследования я обнаружил, что во втором случае System.in больше не указывает на ByteArrayInputStream, а скорее (старый?) BufferedInputStream. Я не понимаю, почему это может происходить (возможно, из-за появления нового потока?) И как мне преодолеть эту проблему?

...