使用mock来模拟基类中的方法或模拟静态方法



我正在尝试模拟外部API调用,但代码结构我不知道mockito是否会有所帮助。

我有一个简单控制器:

public class SimpleController extends Anothercontroller
{
  @RequestMapping("/classA")
  {
    .......
    String response = postCall(url, .....);
   }
}
public class AnotherController
{
  public String postCall (String url, ......)
  {
    //This is the apache library to make post calls
    return WebUtil.post(......);
  }
}

所以现在我需要模拟postCall,它是对外部服务的调用。

在这里我可以在两个地方嘲笑:

1) postCall()在SimpleController,然而,我不知道如何做到这一点,因为它倾向于继承比组合。

2) WebUtil.post(.....)然而,我不知道mockito如何模拟静态方法。

我不想重构代码结构,因为还有很多其他的代码依赖于它。

1) postCall()在SimpleController,但我不知道怎么做因为它更倾向于继承而不是组合。

这在Mockito使用间谍时是可能的。除非另有指定,否则间谍是使用真实方法的对象的模拟。

// spyController will use real methods expect for postCall()
SimpleController spyController = Mockito.spy(new SimpleController());
Mockito.doReturn("mockedString").when(spyController).postCall();

2) WebUtil.post(.....)然而,我不知道mockito如何可以模拟一个静态方法。

这在Mockito中是不可能的,但有两个解决方案:

  1. 使用PowerMock,它允许静态模拟。重构代码,使其不直接调用静态方法。@mdewit的回答中已经解释了这一点,所以我只让你阅读那里的细节。

我个人认为重构是最干净的解决方案,因为拥有静态依赖是邪恶的。如果出于某种原因,您不能或不想更改生产代码,那么Mockito.spy()是一个很好的方法。

如果你被允许修改AnotherController,你可以这样做:首先你把WebUtil包装在另一个类中,像这样:

public class WebUtilWrapper {
     String post(.....) {
          return WebUtil.post(.....);
     }
}

然后,向AnotherController添加一个构造函数,将WebUtilWrapper作为参数。这个构造函数将在单元测试中使用:

public class AnotherController {
     private WebUtilWrapper wrapper;
     public AnotherController() {
          //default constructor
          this(new WebUtilWrapper());             
     }
     public AnotherController(WebUtilWrapper wrapper) {
          this.wrapper = wrapper;
     }
     public String postCall (String url, ......) {
          //This is the apache library to make post calls
          return this.wrapper.post(......);
     }
}

最后还要向您的SimpleController添加参数化构造函数。

 public class SimpleController extends Anothercontroller {
      public SimpleController() {
           super();
      }
      public SimpleController(WebUtilWrapper wrapper) {
           super(wrapper);
      }
      .
      .
      .

现在您可以在单元测试中模拟WebUtilWrapper(而不是WebUtil)。剩下的代码将正常工作,因为默认构造函数仍然可用。

在本例中,PowerMock是模拟WebUtil.post()的合理选项。他们有一个使用Spring和@Rule的例子,默认方式是使用@RunWith,但在Spring中,您通常已经使用了该注释。

https://github.com/jayway/powermock/blob/master/examples/spring-mockito/src/test/java/org/powermock/examples/spring/mockito/SpringExampleTest.java

相关内容

  • 没有找到相关文章

最新更新