3

我有WidgetProcessor一个依赖于另一个类的类,FizzChecker

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()第一次调用它时返回 false (因此循环永远不会执行)
  • fizzChecker.hasMoreBuzz()第 5 次调用时返回 false

我正在尝试弄清楚如何使用 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

提前致谢。

4

2 回答 2

7

您可以将多个值传递给thenReturn,或继续链接。对存根方法的连续调用将按顺序返回操作,对所有调用重复最终操作。例子:

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

最后一点:实际上,您可能会发现您需要协调多个调用(例如hasMoreBuzzand getNextBuzz)。如果它开始变得复杂,并且您预见到要在很多测试中编写它,请考虑跳过 Mockito 而只是实现一个FakeFizzChecker.

于 2013-02-18T02:24:29.657 回答
0

尝试使用Answers。这将允许您在调用 hasMoreBuzz() 方法时执行代码。

查看上面提供的链接中的示例。如果您创建一个 Answer 对象,并实现 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();
    }
}
于 2013-02-18T00:27:25.567 回答