2013-02-18 2 views
3

У меня есть класс WidgetProcessor что имеет зависимость от другого класса, FizzChecker:Переменный выход Mockito издевается

public class FizzChecker { 
    public boolean hasMoreBuzz() { 
     // Sometimes returns true, sometimes returns false. 
    } 
} 

Этот hasMoreBuzz() метод вызывается внутри WidgetProcessor как так:

public class WidgetProcessor { 
    public int process() { 
     while(fizzChecker.hasMoreBuzz()) { 
      // ... process stuff in here 
     } 
    } 
} 

Я хочу написать тестовые примеры, когда:

  • fizzChecker.hasMoreBuzz() возвращает ложь первый раз, когда он называется (отсюда петля никогда не выполняет)
  • fizzChecker.hasMoreBuzz() возвращает ложные на 5-й раз он называется

Я пытаюсь выяснить, как сделать это с Mockito. Пока что моя лучшая (страшная) попытка:

WidgetProcessor fixture = new WidgetProcessor(); 
FizzChecker mockFizzChecker = Mockito.mock(FizzChecker.class); 

// This works great for the first test case, but what about the 2nd 
// where I need it to return: true, true, true, true, false? 
Mockito.when(mockFizzChecker).hasMoreBuzz().thenReturn(false); 

fixture.setFizzChecker(mockFizzCheck); 

fixture.process(); 

// Assert omitted for brevity 

Заранее спасибо.

ответ

5

pass in multiple values to thenReturn, or keep chaining. Последовательные вызовы обрезанного метода возвращают действия последовательно, повторяя окончательное действие для всех вызовов. Примеры:

// will return true four times, and then false for all calls afterwards 
when(mockFizzChecker.hasMoreBuzz()).thenReturn(true, true, true, true, false); 
when(mockFizzChecker.hasMoreBuzz()) 
    .thenReturn(true) 
    .thenReturn(true) 
    .thenReturn(true) 
    .thenReturn(true) 
    .thenReturn(false); 
// you can also switch actions like this: 
when(someOtherMock.someMethodCall()) 
    .thenReturn(1, 2) 
    .thenThrow(new RuntimeException()); 

Вы, вероятно, хотите, чтобы установить их отдельно:

public class WidgetProcessorTest { 
    private WidgetProcessor processor; 
    private FizzChecker mockFizzChecker; 

    @Before public void setUp() { 
    processor = new WidgetProcessor(); 
    mockFizzChecker = Mockito.mock(FizzChecker.class); 
    processor.setFizzChecker(mockFizzChecker); 
    } 

    @Test public void neverHasBuzz() { 
    when(mockFizzChecker.hasMoreBuzz()).thenReturn(false); 
    processor.process(); 
    // asserts 
    } 

    @Test public void hasFiveBuzzes() { 
    when(mockFizzChecker.hasMoreBuzz()) 
     .thenReturn(true, true, true, true, false); 
    processor.process(); 
    // asserts 
    } 
} 

Последнего примечание: На самом деле, вы можете обнаружить, что вам нужно координировать несколько вызовов (например, hasMoreBuzz и getNextBuzz). Если он начнет усложняться, и вы предвидите писать это во многих тестах, попробуйте пропустить Mockito и вместо этого просто implementing a FakeFizzChecker.

1

Попробуйте использовать Answers. Это позволит вам выполнить код при вызове метода hasMoreBuzz().

Посмотрите на пример в приведенной выше ссылке. Если вы создаете объект «Ответ» и реализуете метод answer() для хранения счетчика, вы можете принять действие на основе значения этого счетчика.

Редактировать: Я написал программу быстрого тестирования, чтобы проверить это. Вот он:

package com.ejk; 
import org.junit.Test; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 
import static org.mockito.Mockito.when; 
import static org.mockito.Mockito.mock; 

public class SO { 
    @Test 
    public void testIt() {   
     IFoo mock = mock(IFoo.class); 
     MyAnswer myAnswer = new MyAnswer(); 
     when(mock.doFoo()).then(myAnswer); 
     for (int i=1; i<10; i++) { 
      System.out.println(i+ ") " + mock.doFoo()); 
     } 
    } 
    class MyAnswer implements Answer<Boolean> { 
     int counter = 1; 
     @Override 
     public Boolean answer(InvocationOnMock invocation) throws Throwable { 
      return (counter++ == 5) ? Boolean.FALSE : Boolean.TRUE; 
     } 

    } 
    interface IFoo { 
     boolean doFoo(); 
    } 
} 
Смежные вопросы