我可以使用 doReturn 将 returns 与 PowerMockito 链接起来吗?

Can I chain returns with PowerMockito using doReturn?

我有一个方法调用,第一次调用时需要 return valueA,第二次调用时需要 valueB。我正在使用 PowerMockito 间谍,所以如果我只需要 return 一个值,它看起来像这样:

PowerMockito.doReturn(valueA).when(mockedObject, "methodName");

看来我可以像这样链接 returns:

PowerMockito.when(mockedObject, "methodName").thenReturn(valueA).thenReturn(valueB);

但我需要用 doReturn 指示链式 returns 以便真正的 methodName() 不会在我的 Spy 上调用。

我试过了,但 Eclipse 给我一个错误,说它甚至无法编译:

PowerMockito.doReturn(valueA).doReturn(valueB).when(mockedObject, "methodName");

甚至可以用 doReturn 和 powermockito 链接 returns 吗?如果可以,怎么做?

我不这么认为。相反,您可以使用如下所示的 doAnswer 和 Queue 来实现它

@Test
public void testReturnChain() throws Exception {
    Example example = new Example() {
        public String getValue() {
            return null;
        }
    };
    Example mockExample = spy(example);
    PowerMockito.doAnswer(new Answer<String>() {
        private final Queue<String> values = new LinkedList<String>(Arrays.asList("firstValue", "secondValue"));

        public String answer(InvocationOnMock invocationOnMock) throws Throwable {
            return values.poll();
        }
    }).when(mockExample, "getValue");

    System.out.println(mockExample.getValue());
    System.out.println(mockExample.getValue());
    System.out.println(mockExample.getValue());
}

试试这个:

((PowerMockitoStubber) PowerMockito.doReturn(valueA).doReturn(valueB))
    .when(mockedObject, "methodName");

简而言之,我认为您在 PowerMockito 中发现了一个漏洞 API。 这可能是一个很好的提交请求请求,或者在至少作为功能请求提交。

发生的事情是 org.powermock.api.mockito.PowerMockito.doReturn(等)将 return 变成 PowerMockitoStubber implementation, which extends Mockito's Stubber; under the hood, PowerMockitoStubberImpl extends StubberImpl。因为 PowerMock 不需要更改功能,所以它不会覆盖这些调用; PowerMockito.doReturn(foo).doReturn(bar) 中的第二个 doReturn 将调用 Mockito 的 StubberImpl 和 return 一个 Mockito Stubber。

这是个问题,因为在过渡到 Stubber 时,您会丢失 PowerMockito when 签名,例如您需要的签名。 简而言之,PowerMockito doVerb 调用支持链接,并且支持反射式或按名称引用方法,但目前不能同时使用。


在内部,StubberImpl 遵循构建器模式,return在每次调用后自动运行:

public Stubber doCallRealMethod() {
    answers.add(new CallsRealMethods());
    return this;
}

因为 this 指的是 PowerMockitoStubberImpl 子类,所以很容易 将 Stubber 转换为 PowerMockitoStubber 以访问其他方法。对于上述解决方法,您自己进行转换:

((PowerMockitoStubber) PowerMockito.doReturn(valueA).doReturn(valueB))
    .when(mockedObject, "methodName");

作为长期解决方案,因为任何 returns PowerMockitoStubber 必然 returns Stubber,这可能会为所有 PowerMockito 用户修复纯粹通过接口覆盖(注意 caveats listed on Joseph D. Darcy's Oracle Weblog)。我还没有测试过这个,但这可能很简单:

/* in PowerMockitoStubber.java, for each doVerb method: */
@Override public PowerMockitoStubber doNothing();

此时您只需调整 return 类型:

@Override public PowerMockitoStubber doNothing() {
  super.doNothing();
  return this;
}

从 PowerMock v1.6.5 开始,您可以将多个值传递给 doReturn(Object toBeReturned, Object... othersToBeReturned)

private static class Example {
    public String getValue() {
      return null;
    }
  }

  @Test
  public void testReturnChain() throws Exception {
    Example example = new Example();
    Example mockExample = PowerMockito.spy(example);
    PowerMockito.doReturn("firstValue", "secondValue").when(mockExample, "getValue");

    assertEquals("firstValue", mockExample.getValue());
    assertEquals("secondValue", mockExample.getValue());
    assertEquals("secondValue", mockExample.getValue());
  }

行为与 thenReturn(T value, T... values) 相同:在调用方法时定义连续的 return 个值 - 最后一个决定进一步调用的行为。