使用mockito操纵参数的存根方法

时间:2011-11-25 20:17:39

标签: java unit-testing methods mockito void

我有以下情况:

class Worker {  
  public Integer somework() {  
      Integer k=0;  
      Helper h= new Helper();  
      h.change(k);  
      return k;  
    }
}

class Helper {
  public void change(Integer k) {
    //k = Some calcs
  }
}

我正在为Worker制作unitests,显然我想模仿Helper课程,以便他的change方法始终将1放入k

我的实际情况更复杂,但此代码代表了问题。谢谢你的帮助。

4 个答案:

答案 0 :(得分:18)

我有一个定义如下的方法:

class Template{
   public void process(Object rootMap, StringWriter out){
 .......   
  }
 }

我将向您展示如何更改/修改“out”(StringWriter)引用。

private final Template mocktTemplate = mock(Template.class);
doAnswer(new Answer<StringWriter>() {

            public StringWriter answer(InvocationOnMock invocation)
                    throws Throwable {
                Object[] args = invocation.getArguments();
                if (args[1] instanceof StringWriter) {
                    StringWriter stringWriter = (StringWriter) args[1];
                    stringWriter.write("Email message");
                }
                return null;
            }
        }).when(this.mocktTemplate).process(anyObject(),any(StringWriter.class));

现在,当您进行实际调用时:

msgBodyTemplate.process(model, msgBodyWriter);

msgBodyWriter中Stringbuffer ref的值为“Email message”;不论它早期的价值。

答案 1 :(得分:4)

至于@JB Nizet的观点,是的,重构可测试性是件好事。通常,重构以使代码更易于测试会导致代码更好地用于其他原因 - 分离关注点等等。这并不总是可行的。说这不是你的代码,或者你有其他要求不管它(因为许多其他类依赖于它的方式)或其他什么。

如果我理解你需要做什么,我认为你可以用间谍来做:

Worker workerUnderTest = new Worker();
Worker spiedWorkerUT = spy(workerUnderTest);
Helper mockHelper = mock(Helper.class);
when(spiedWorkerUT.createHelper()).thenReturn(mockHelper);
Integer actual = spiedWorkerUT.someWork();
verify(mockHelper).change(0);

然后使用spiedWorkerUT而不是workerUnderTest来运行测试。

并不总是可以避免实例化你想要模拟的东西。为此,有PowerMock

Helper mockHelper = mock(Helper.class);
whenNew(Helper.class).withNoArguments().thenReturn(mockHelper);

答案 2 :(得分:4)

我认为doAnswer是处理void方法的最佳方法,其中方法操纵给定的参数。

doAnswer(new Answer() {
  public Object answer(InvocationOnMock invocation) {
      Object[] args = invocation.getArguments();
      Mock mock = invocation.getMock();
      return null;
  }})
.when(mock).someMethod();

基本上,在获得参数后,您可以进行任何您想要的修改。有blog post解释了一下。

答案 3 :(得分:2)

我会更改方法签名并使其以Helper实例作为参数。调用者将创建帮助程序并将其传递给somework方法。测试将通过模拟助手。

如果无法做到这一点,至少调用受保护的工厂方法来创建帮助程序,并在测试somework方法时模拟此工厂方法,以使其返回模拟帮助程序:

class Worker {  
    public Integer somework(){  
        Integer k=0;  
        Helper h= createHelper();  
        h.change(k);  
        return k;  
    }

    // this method may be mocked when testing somework, to return a mock helper.
    protected Helper createHelper() {
        return new Helper();
    }
}