Can I chain returns with PowerMockito using doReturn?

给你一囗甜甜゛ 提交于 2020-01-06 03:34:08

问题


I have a method call that needs to return valueA the first time it is called and valueB the second time it is called. I'm using a PowerMockito spy, so if I were just needing to return one value it would look like this:

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

It looks like I can do chained returns like this:

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

But I need to indicate chained returns with doReturn so that the real methodName() isn't called on my Spy.

I've tried this, but Eclipse gives me an error saying that it won't even compile:

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

Is it even possible to chain returns with doReturn and powermockito? If so, how?


回答1:


I don't think so. Rather, You can achieve it with using doAnswer and Queue like below

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



回答2:


Try this:

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

In short, I think you've found a hole in the PowerMockito API. This may be an excellent thing to submit as a pull request, or at least to file as a feature request.

What's happening is that org.powermock.api.mockito.PowerMockito.doReturn (et al) will return a PowerMockitoStubber implementation, which extends Mockito's Stubber; under the hood, PowerMockitoStubberImpl extends StubberImpl. Because PowerMock doesn't need to change the functionality, it does not override these calls; the second doReturn in PowerMockito.doReturn(foo).doReturn(bar) will invoke Mockito's StubberImpl and return a Mockito Stubber.

This is a problem, because in the transition to Stubber, you lose the PowerMockito when signatures, such as the one you need. In short, PowerMockito doVerb calls do support chaining, and do support referring to Methods reflectively or by name, but currently not both at the same time.


Internally, StubberImpl follows the builder pattern, returning itself after every call:

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

Because this refers to the PowerMockitoStubberImpl subclass, it would be easy to cast the Stubber to PowerMockitoStubber to get access to the additional methods. For the above workaround, you're making the cast yourself:

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

As a long term solution, because anything that returns PowerMockitoStubber necessarily returns Stubber, this may be possible to fix for all PowerMockito users purely through an interface override (noting the caveats listed on Joseph D. Darcy's Oracle Weblog). I haven't tested this, but it may be this easy:

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

At which point you would simply have to adapt the return type:

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



回答3:


Since PowerMock v1.6.5 you can pass multiple values to 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());
  }

The behavior is the same as thenReturn(T value, T... values): define consecutive return values when the method is called - and the last one determines the behavior of further calls.



来源:https://stackoverflow.com/questions/34190095/can-i-chain-returns-with-powermockito-using-doreturn

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!