2016-08-14 4 views
2

У меня есть конкретный проект словаря, который принимает входные данные пользователя и записывает их в базу данных. Входы (на данный момент) принимаются через сканеры (System.in) и у меня есть несколько случаев, например:Схема тестирования JUnit

  1. Введите слово и определение
  2. Введите синонимы
  3. печати словаря

вещи, как это. Как я могу копировать пользовательские входы с помощью JUnit?

ответ

2

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); 
} 

Второй пакет частного для тестирования.

+0

Это мой макет проекта. У меня есть класс под названием «Инициализатор», у которого есть поле, которое я создал в качестве объекта «Словарь». «Инициализатор» создает объект «InputReceiver», который отображает меню, указанное выше. В зависимости от ввода (a, b, c) он вызывает методы addWord(), addSynonym(), printAll() в другом классе под названием «inputHandler». Это основная часть моей логики. «InputHandler решает, стоит ли добавлять слово, если оно уже существует, и если ему разрешено иметь синонимы, а также создает транзитивность для синонов. –

+0

Я хочу создать тест JUnit, чтобы пройти через пример взаимодействия с пользователем, например, Прокрутите строки RNG и создайте слова и определение, чтобы автоматически заполнить мои таблицы для меня. –

+0

Благодарим вас за эти рекомендации. Дизайн выглядит хорошо. Итак, вы хотели бы сделать интеграционный тест: тест, который проверяет всю цепочку компоненты от InputReceiver до реальной вставки, так что без насмехающегося поведения? – davidxxx

3

Этот вопрос довольно широк; но существенная часть, чтобы получить это: чтобы получить максимальную отдачу от JUnit, вы должны увидеть как часть автоматизации. Таким образом, вы должны сосредоточиться на удалении чего-либо, что предотвращает это.

Другими словами: вашему приложению нужен интерфейс, который вы можете использовать для «подачи» его с помощью ввода. Значение: ваше приложение должно не содержать любой код, который читается из System.in. Вместо этого ваше приложение должно иметь простой интерфейс, например addWordWithDefinition(String word, String definition). И он должен иметь методы для запроса такой информации позже.

А теперь писать TestCase так просто, как:

@Test 
public void testAddAndGet() { 
    String someWord = "whatever"; 
    String definition = "who cares"; 
    YourApplication underTest = new YourApplication(... 
    underTest.addWordWithDefinition(someWord, definition); 
    assertThat(underTest.getDefinitionFor(someWord), is(definition)); 

Вы идете оттуда; вы думаете об угловых случаях (например, один или оба аргумента равны нулю) и т. д. Вы пытаетесь абсолютным не проверить внутренности вашей реализации. Итак, это идеально, когда вы меняете свой механизм «упорства»; ваши тесты все еще работают.

+0

Я бы пошел с данным, когда, тогда также;) – Sarseth

+1

@Sarseth Это так, я говорю, что его вопрос на самом деле довольно широкий. Я не хотел вдаваться в «это то, как вы пишете единичные тесты в целом»; так как здесь слишком много вариантов, путей, стратегий. Было бы слишком много для одного ответа; и, вероятно, слишком много для человека, который просто начинает тестирование модулей. Но вы правы: это может быть хорошим моментом для «новичков», чтобы сделать больше исследований «как писать модульные тесты». – GhostCat

+0

Когда вы говорите простой интерфейс, что вы имеете в виду, объект Swing или иначе? –

 Смежные вопросы

  • Нет связанных вопросов^_^