2012-04-21 4 views
0

У меня есть функциональность, которую я хочу издеваться над вызовом из main (статический: я тоже об этом читал - jmock mocking a static method). Недавно я прочитал, что JMock не поддерживает насмешку статических функций. Ну, ассоциированный код (который дает мне проблемы) должен быть вызван из основных, и должен быть в классе с основнымами ...Jmock - как автоматизировать и изнашивать вход пользователя в консоль?

Sample source

Test code

Прямо сейчас, я хочу, чтобы обеспечить что у моей основной есть тест, чтобы убедиться, что файл существует до его продолжения. Проблема в том, что у меня есть моя программа, получающая пользовательский ввод с консоли, поэтому я не знаю, как издеваться над этим? Достаточно ли я перейти на этот уровень детализации, указав в каждой точке пути, что происходит, чтобы я мог писать только одну операцию в функции, которая возвращает вход пользователя? Я знаю, что, чтобы хорошо писать тесты, когда тесты запускаются, они не должны запрашивать ввод пользователя, я должен как-то указывать его в своих тестах.

Я думаю, что это имеет отношение к следующему: How to use JMock to test mocked methods inside a mocked method Я не так хорошо с JMock ...

+0

В чем именно заключается цель этого? У вас есть фактический модульный тест? Я не вижу смысла использовать JMock. – jmend

+0

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

ответ

0

Ответ Стефана Биркнера дал мне направление, которое мне нужно для решения этой проблемы. Я опубликовал код, который я использовал для решения этой проблемы.

Solved tests: Birkner's version (recommended)

Solved tests: piped version

Changed source:

ПОЧЕМУ: Что происходит, с библиотекой Birkner, вы можете только когда-либо читал столько ввод как инстанцировании с правилом первоначально. Если вы хотите итеративно писать в конечную точку, вы можете сделать это с помощью взлома трубки, но это не имеет большого значения, вы не можете писать на вход по каналу, пока функция фактически запущена, поэтому вы может также использовать версию Биркнера, его @Rule более кратким.

Объяснение: В обоих хака трубы и с кодом Birkner, в самом клиенте тестируется, несколько вызовов, чтобы создать какой-либо объект, который считывает с System.in вызовет проблемы блокировки, где после того, как первый объект открыл подключение к трубе или к System.in, другие не могут. Я не знаю, почему это точно для кода Биркнера, но с Pipe я думаю, что это потому, что вы можете открыть только один поток для объекта. Обратите внимание, что если вы вызовете ближайший буферизированный считыватель и затем попытаетесь повторно открыть System.in в своем клиентском коде после его вызова из теста, то вторая попытка открыть не будет выполнена, потому что канал со стороны автора закрыт также.

Решение: Простой способ решить эту проблему и, вероятно, не лучший, поскольку требует изменения источника фактического проекта, но не ужасающим образом (пока). Поэтому вместо того, чтобы иметь в основе фактического проекта несколько созданий BufferedReader, создайте буферизованный читатель и передайте одну и ту же ссылку на читателя или сделайте ее частной переменной класса. Помните, что если вам нужно объявить статичным, что вы не должны инициализировать его в статическом контексте, потому что если вы это сделаете, то при запуске тестов System.setIn получит имя ПОСЛЕ того, как читатель был инициализирован вашим клиентом. Таким образом, он будет опросить все вызовы readLine/any, как и будет, если вы попытаетесь создать несколько объектов из System.in. Обратите внимание, что для чтения ваших разделов между вызовами вашего читателя, в данном случае BufferedReader, вы можете использовать символы новой строки для их разделения в исходной настройке. Таким образом, он возвращает то, что вы хотите в каждом вызове тестируемого клиента.

2

Если метод readInput() делает что-то, как, скажем:

BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
return in.readLine(); 

Тогда вам, возможно, удастся пройти тест, который выглядит примерно так:

InputStream oldSystemIn = System.in; 
InputStream mockSystemIn = context.mock(InputStream.class); 
System.setIn(mockSystemIn); 
context.checking(new Expectations() {{ 
    // mock expected method calls and return values 
}}); 
// execute 
// verify 
System.setIn(oldSystemIn); 
+0

Спасибо, что это, безусловно, хороший ответ. Но теперь, когда я думаю об этом, я понимаю, что мне тоже нужно высмеять консоль. Вот мой источник испытывается (что-то близко, я подрезал многого): http://ideone.com/Tmh1M Вот что у меня в порядке насмешливая: http://ideone.com/QnL2a И вот за исключением того, что я получаю: http://ideone.com/OEOS8 Как вы можете ясно видеть в моих ожиданиях, я прямо говорю, что планирую напечатать ту же самую строку, и Я уточнил это в моих ожиданиях. Но исключение гласит, что это было неожиданно. Я не понимаю ... –

1

Вы можете использовать System Rules вместо издевательств System.out и System.in.

public void MyTest { 
    @Rule 
    public TextFromStandardInputStream systemInMock = emptyStandardInputStream(); 

    @Test 
    public void readTextFromStandardInputStream() { 
    systemInMock.provideText("your file name"); 
    //your code that reads "your file name" from System.in 
    } 
} 
+0

Как мне заставить его работать в контексте ожидания? Нужно ли это быть правилом? Я имею в виду, как я могу поэтапно применять то, что хочу? или что, если у меня есть BufferedReader в цикле? как установить, какие последующие значения следует читать? –

+0

На самом деле, я нашел, что я пытался сделать с setIn с моим собственным источником, это то, что вы только что предложили. Самой большой проблемой является отправка нескольких уникальных произведений в программу. Я попытался решить проблему, переопределив их способ решения этой проблемы с помощью pipedoutputstream и записывая трубку перед тестом. Но теперь мне нужно найти способ написать трубку, пока она работает ... –