GhostCat является правильным. Я хотел бы завершить свой ответ.
В приложении есть 2 отдельные обязанности:
- захватывая запросы пользователей для каждого из ваших бизнес-кейсов (Введите слово и определение, введите синонимы, Print словарем): ответственность интерфейса пользователя.
- Обработка логики: логическая ответственность.
Хорошая конструкция пытается избежать смещения обязанностей. Итак, вы должны создать класс для:
- Захват запросов пользователей. Он захватывает пользовательский ввод из System.in и отправляет данные в соответствующий метод класса обработки.
- обработка логики. это логический класс.
В чем его преимущество?
Логика вашего приложения теперь находится в классе, обрабатывающем логику.
Таким образом, вы можете сконцентрировать модульный тест на этом классе, чтобы проверить, что ваше приложение обрабатывает логику, как ожидалось.
С таким дизайном Вам не нужно беспокоиться о сканере, так как это зрелый компонент, который работает: вам не нужно тестировать устройство, это работает.
- Edit: Для ответа на ваш комментарий о том, как реализовать интеграционный тест с System.in
Я посмотрел код.
Во-первых, с вашим фактическим кодом вы не могли бы выполнить интеграционный тест со сканером, который полагался бы на несколько входных данных, потому что классические издевательские инструменты, такие как Mockito, не позволяют это делать (класс является окончательным).
Вы можете заглушить входной поток, но, как в том же методе, вы берете несколько входов (выбор опции + значения), вы не можете заглушить два входа.
Итак, мы должны найти трюк для обхода его. Способом решения проблемы является создание двух способов использования вашего приложения: одно со входом, введенным один за другим пользователем, а другое со всеми входами, введенными за один раз с разделителями для вашего модульного теста.
Все не работает, но вы можете следовать принципу.
тест
Устройство будет так:
@Test
public void printOptionWithAddedWordInDictionary() throws Exception {
final ByteArrayInputStream inputStreamStubbed = new ByteArrayInputStream("a|dog|super animal!".getBytes());
InputReceiver inputReceiver = new InputReceiver(inputStreamStubbed, "\\|");
inputReceiver.printOptions();
}
И, как вы видите, у вас есть два конструктора теперь и два новых частных поля:
private InputStream inputStream;
private Scanner input;
public InputReceiver() {
inputStream = System.in;
scanner = new Scanner(inputStream);
}
// for unit testing
InputReceiver(InputStream inputStream, String delimiter) {
this.inputStream = inputStream;
scanner = new Scanner(inputStream);
scanner.useDelimiter(delimiter);
}
Второй пакет частного для тестирования.
Это мой макет проекта. У меня есть класс под названием «Инициализатор», у которого есть поле, которое я создал в качестве объекта «Словарь». «Инициализатор» создает объект «InputReceiver», который отображает меню, указанное выше. В зависимости от ввода (a, b, c) он вызывает методы addWord(), addSynonym(), printAll() в другом классе под названием «inputHandler». Это основная часть моей логики. «InputHandler решает, стоит ли добавлять слово, если оно уже существует, и если ему разрешено иметь синонимы, а также создает транзитивность для синонов. –
Я хочу создать тест JUnit, чтобы пройти через пример взаимодействия с пользователем, например, Прокрутите строки RNG и создайте слова и определение, чтобы автоматически заполнить мои таблицы для меня. –
Благодарим вас за эти рекомендации. Дизайн выглядит хорошо. Итак, вы хотели бы сделать интеграционный тест: тест, который проверяет всю цепочку компоненты от InputReceiver до реальной вставки, так что без насмехающегося поведения? – davidxxx