Power Mockito 在方法私有时抛出 "Unfinished stubbing" 错误,但在方法受保护时不会抛出错误

Power Mockito Throws "Unfinished stubbing" error when method is private, but not error when method is protected

我正在尝试测试使用正确参数调用的方法 'reallyCoolMethod'。问题是存根 'getSillyString' 方法导致错误。当方法 'getSillyString' 为私有时,测试将在第二次 doReturn 时失败:

doReturn("superSilly").when(spy, "getSillyString", 5, false);

但是当方法被保护时,测试将通过。错误是:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:36)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!

这是正在测试的 class:

import java.util.Random;

@Singleton
public class FooBar {

  @Inject
  public FooBar(Foo foo, Bar bar) {
    this.foo = foo;
    this.bar = bar;
  }

  @POST
  @Path("foos/")
  public fooAction createFoo() {

     word1 = getSillyString(4, true);
     word2 = getSillyString(5, false);

     int id = reallyCoolMethod(word1,word2);
  }

  private String getSillyString(int size, boolean allCaps){
  }
}

这是测试:

import static org.mockito.Mockito.verify;

import org.junit.Test;
import org.mockito.Mockito;

import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.spy;

import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
public class FooTest {

    @Test
    public void testCreateFoo() throws Exception {

      Foo foo = Mockito.mock(Foo.class);
      Bar bar = Mockito.mock(Bar.class);
      FooBar resource = new FooBar(foo, bar);
      FooBar spy = spy(resource);

      doReturn("reallySilly").when(spy, "getSillyString", 4, true);
      doReturn("superSilly").when(spy, "getSillyString", 5, false);

      doReturn(1).when(spy).reallyCoolMethod(Mockito.anyString(),Mockito.anyString());
      spy.createFoo();
      verify(spy).reallyCoolMethod(Mockito.eq("reallySilly"),Mockito.Eq(superSilly));
    }

}

这里的真正答案是:您通过将 class 的基本元素放入 private 方法来创建 hard-to-test 代码。

换句话说:如果那个东西对您的生产代码如此重要,那么更好的答案是将底层功能放在它自己的 class 中。所以,你创建了一些接口:

public interface SillyService {
  public String getSillyString();
}

然后你使用依赖注入提供"some kind"实现给需要这个服务的class。

模拟私有方法的愿望总是糟糕的设计决定的结果。因此,答案不在 Mockito 或 PowerMock 中,而是通过退后一步 改进 该设计。

对于初学者,可以观看这些 videos 来学习如何编写 可测试 代码。

除此之外:请注意 PowerMock 会影响您可以使用 Mockito 执行的操作 - 因为 PowerMock 附带了相当多的 Mockito 后级版本。我的个人建议:摆脱对 PowerMock 的需求;而只是使用 latest/greatest 版本的 Mockito。