2015-04-03 3 views
4

Я пишу JUnit для программы, созданной в упражнении. Это означает, что тест должен охватывать как можно больше случаев, и я не влияю на то, как определенные вещи в программе реализованы. Кроме того, программа запускает бесконечный цикл, где в какой-то момент требуется, чтобы пользователь что-то вводил.
Для теста JUnit я запускаю программу в другом Thread и имитирую пользовательский ввод из JUnit Thread.Java I/O - Имитировать вход для System.console()

Пока все работает нормально, если программа считывает пользовательский ввод от System.in, так как этот поток можно легко заменить. Но есть также возможность, что программа взаимодействует с System.console(), который в настоящее время не может быть покрыт моим тестом.

Есть ли возможность имитировать вход для System.console(), например. заменив его входной источник другим потоком?

(NB:. Тест JUnit должен использовать Java 6 без каких-либо внешних библиотек (кроме JUnit и Hamcrest))

Edit: К сожалению, я не могу изменить классы программы для тестирования.

+0

Конструктор вашего класса должен принять объект 'Console', чтобы вы могли * вставить * его. Затем в тесте вам нужно будет создать экземпляр * mock * 'Console', который вам нужно будет передать конструктору. –

+0

@SvetlinZarev см. Мое редактирование. Другого пути нет? – darktestuser

ответ

4

После просмотра исходного кода JDK я нашел Console класс читает данные из стандартного ввода (System.in):

reader = new LineReader(StreamDecoder.forInputStreamReader(new FileInputStream(FileDescriptor.in), readLock, cs)); 

Где FileDescriptor.in является постоянной, указывающей на реальный стандартный ввод (public static final FileDescriptor in = standardStream(0);). Итак, если вы замените System.in, используя System.setIn(), консольный класс по-прежнему будет использовать стандартный стандартный ввод.

Ваш единственный вариант - заменить объект Console на mock.

3

Я думаю, вам нужно создать абстракцию для консоли, как описано в this post. И используйте эту абстракцию в коде вместо System.console(). Затем вы можете издеваться над абстракцией вы контроль в тестах.

EDIT: Другим решением, которое больше всего связано, является изменение байтового кода System.console() (или базовых классов солнца) при его загрузке в JVM. Это делается путем предоставления вашей собственной реализации ClassLoader, и вы можете найти информацию о том, как это сделать. Я не уверен, что вы хотите пойти в эту кроличью нору ...

+0

Поскольку я не могу влиять на то, что фактическая программа использует как консоль, абстракция будет бесполезной, поскольку программа все равно будет использовать 'System.console()', а не мою пользовательскую консоль. Это было бы иначе, если бы вы могли изменить используемую консоль, как это возможно с помощью 'System.in', используя' System.setIn() ' – darktestuser

0

В пути я могу придумать использование насмешливого класса сканера. Например

 int i = sc.nextInt(); 

Теперь издеваться реализация будет называться

public void Scanner getScanner(){ 

    } 


    // inject mock object for unit testing and in prod , 
     real object with input stream from console 
    public void Scanner setScanner(Scanner scanner){ 

    } 
+0

Он спрашивает о' Console' не 'Scanner' –

+0

, но в основном он хочет поток чтения, который также можно сделать из сканера –

+0

Я не хочу читать поток. Я хочу имитировать вход и, следовательно, манипулировать ** исходным источником ** 'System.console()'. – darktestuser

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