2013-09-12 4 views
3

У меня есть метод следующегоMockito издеваться методом с бесконечным циклом

public class ClientClass { 

    public void clientMethod() { 
     while(true){ 
      doSomethings..... 
     } 
    } 
} 

Я пытаюсь проверить с помощью Mockito. Я могу сделать вызов clientMethod, но поскольку в clientMethod есть некоторое время (true), вызов никогда не возвращается, и я никогда не дойду до своих утверждений assert, которые (конечно) возникают после вызова clientMethod(). Есть ли способ остановить цикл после одной итерации цикла из моего тестового примера?

+0

Как программа выйдет из цикла, когда код будет работать? Можете ли вы имитировать такое же условие? –

ответ

2

Технически вы не можете разбить бесконечный цикл в тесте, не выбрасывая исключение изнутри. Если в цикле есть что-то внутри, вы можете высмеивать, то это может вызвать для вас исключение.

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

Если вы по-прежнему убеждены в том, что бесконечный цикл это лучший способ пойти сюда, то вы можете выполнить небольшое разложение, чтобы сделать вещи более проверяемым:

public class ClientClass { 

    // call me in production code 
    public void clientMethod() { 
    while(true){ 
     doSomethings(); 
    } 
    } 

    // call me in tests 
    void doSomethings(){ 
    // loop logic 
    } 
} 
0

Это было источником небольшого разочарования мне ... потому что мне нравится начинать с самых сложных графических приложений с помощью консольного обработчика.

Язык, который я использую здесь, это Groovy, который является своего рода чудесным расширением Java и который может быть смешанным с простой старой Java.

class ConsoleHandler { 

    def loopCount = 0 
    def maxLoopCount = 100000 

    void loop() { 
     while(! endConditionMet()){ 
      // ... do something 
     } 
    } 

    boolean endConditionMet() { 
     loopCount++ 
     loopCount > maxLoopCount // NB no "return" needed! 
    } 

    static void main(args) { 
     new ConsoleHandler().loop() 
    } 
} 

... в классе тестирования (также в Groovy), вы можете затем

import org.junit.contrib.java.lang.system.SystemOutRule 
import org.junit.contrib.java.lang.system. 
    TextFromStandardInputStream.emptyStandardInputStream 
import static org.assertj.core.api.Assertions.assertThat 
import org.junit.Rule 
import static org.mockito.Mockito.* 

class XXTests { 
    @Rule 
    public SystemOutRule systemOutRule = new SystemOutRule().enableLog() 
    @Rule 
    public TextFromStandardInputStream systemInMock = emptyStandardInputStream() 
    ConsoleHandler spyConsoleHandler = spy(new ConsoleHandler()) 

    @Test 
    void readInShouldFollowedByAnother() { 
     spyConsoleHandler.setMaxLoopCount 10 
     systemInMock.provideLines('blah', 'boggle') 
     spyConsoleHandler.loop() 
     assertThat(systemOutRule.getLog()).containsIgnoringCase('blah') 
     assertThat(systemOutRule.getLog()).containsIgnoringCase('boggle') 

Прелесть, что здесь происходит, что просто объявляя maxLoopCount язык автоматически создает два метода: getMaxLoopCount и setMaxLoopCount (и вам даже не нужно беспокоиться о скобках).

Конечно, следующий тест будет состоять в том, что «цикл должен выйти, если пользователь вводит Q» или что-то еще ... но точка в TDD заключается в том, что вы хотите, чтобы это было FAIL изначально!

Вышеупомянутые могут быть реплицированы с использованием простой старой Java, если вам необходимо: вы должны создать свой собственный метод setXXX, конечно.

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