Variable output of Mockito mocks

I have a class WidgetProcessor

that has a dependency on another class FizzChecker

,:

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

      

This method hasMoreBuzz()

is called internally WidgetProcessor

as follows:

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

      

I want to write test cases when:

  • fizzChecker.hasMoreBuzz()

    returns false the first time it is called (hence the loop is never executed)
  • fizzChecker.hasMoreBuzz()

    returns false the 5th time it is called

I am trying to figure out how to do this with Mockito. So far, my best (terrible) attempt is:

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

      

Thanks in advance.

+3


source to share


2 answers


You can pass multiple values ​​to thenReturn

or store the chain
. Consecutive calls to the truncated method return actions in sequence, repeating the final action for all calls. Examples:

// 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());

      

You probably want to install them separately:



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

      

One final note: you may actually need to negotiate multiple calls (e.g. hasMoreBuzz

and getNextBuzz

). If it starts to get complicated and you plan on writing this in many tests, try skipping Mockito and just implementFakeFizzChecker

it instead .

+5


source


Try using Answers . This will allow you to execute the code when you call the hasMoreBuzz () method.

Check out the example in the link above. If you create an Answer object and implement the answer () method to store a counter, you can take an action based on the value of that counter.



Edit: I wrote a quick test program to test this. Here he is:

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

      

+1


source







All Articles