重构以编写“漂亮”的JUnit测试

时间:2012-04-27 09:39:14

标签: java refactoring mocking tdd mockito

我想澄清TDD范围内的重构。

在:

class Somclass{
      public void sendMessage(){    
       WebServiceStub stub = new WebServiceStub();     
      ...
      stub.sendMsg();        
      }
    }

后:

class Somclass{
private WebServiceStub stub;

  public void sendMessage(){
    ...
  if(stub == null){
   stub = new WebServiceStub();
  }
  ...
  stub.sendMsg();        
  }
}

所以我想验证sendMsg()方法并使用result生成一些断言。为了具有模拟此存根的可能性,我将此存根局部变量移动到实例变量。这样我就可以将mock存根设置为类,并在测试类中进行verivyings和asserts。例如:

@Test
public void testSMth(){
  wsProvider.setStub(stubMock);
  verify(stubMock).sendMsg();
  ...asserts
}

这种方法不是线程安全的,我应该做一些并发修改。这种修改可能会导致错误。所以在局部变量approce中有线程安全。

此外,我可以创建将返回WebServiceStub实例的Factory。但是这种方法会产生新的课程,因为这种情况经常发生。

有一个问题:如何测试这种情况并进行粗略测试可能导致错误的成本修改?

3 个答案:

答案 0 :(得分:4)

您的班级应该将WebService对象(我拒绝将其称为“存根”)作为字段。

class Someclass{

  @Resource
  private WebService ws;

  public void sendMessage(){

  ws.sendMsg();        
  }
}

应该注入您选择的DI框架。在测试中,您可以将其设置为模拟。没有必要使用懒惰的getter,因为你的观点是不是线程安全的。

答案 1 :(得分:3)

使用constructor injection以避免未设置依赖项的可能性。这将允许您在测试中轻松使用模拟。

如果WebServiceStub类实际上不是线程安全的(但如果JAX-WS生成WebServiceStub,那么你应该知道metro / jax-ws存根通常是线程安全的),那么是的,你将不得不使用工厂。这并不是什么大不了的事,它不应该让你失望那么多。如果需要,可以使用静态内部类。

答案 2 :(得分:0)

它看起来几乎是正确的,但如果stub == Null则永远不会实例化stub。相反,thow ArgumentNullException。 Null永远不应该被接受作为一个有效的论据(除非你有一个非常,非常,非常好的理由)。