【问题标题】:Refactoring in order to write "pretty" JUnit tests重构以编写“漂亮”的 JUnit 测试
【发布时间】:2012-04-27 09:39:13
【问题描述】:

我想澄清 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() 方法并根据结果进行一些断言。为了有可能模拟这个存根,我将这个存根局部变量移动到实例变量。这样我就可以将模拟存根设置为类并在测试类中进行验证和断言。例如:

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

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

我还可以创建将返回 WebServiceStub 实例的工厂。但是这种方法会产生新的类,因为这种情况很常见。

有个问题:这个case怎么测试,goot测试成本修改会不会出错?

【问题讨论】:

  • 您正在混淆自己和其他使用“存根”来引用生成的 WebService 类的人。我知道这是经常使用的,但在单元测试上下文中,“存根”的含义完全不同。

标签: java refactoring mocking tdd mockito


【解决方案1】:

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

class Someclass{

  @Resource
  private WebService ws;

  public void sendMessage(){

  ws.sendMsg();        
  }
}

它应该注入您选择的 DI 框架。在您的测试中,您可以将其设置为模拟。正如您指出的那样,这不是线程安全的。

【讨论】:

  • 有一个问题:在我的 DI 框架(ATG Dynamo)中,类必须有 setter 和 getter。
  • 如果没有设置器,就不可能在测试中设置变量。
  • 哦。我是 .... :-)。我没有遵循这一点的原因 - 我不想将存根用作 Reouce。但可能……我会的。非常感谢)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    它看起来几乎是正确的,但从不实例化存根,如果存根 == Null。相反,使用 ArgumentNullException。 Null 永远不应该被接受为一个有效的论点(除非你有一个非常、非常、非常好的理由)。

    【讨论】:

    • 如果我不清楚,我很抱歉。 “真实”案例的 if() 语句。每次在非测试类中处理代码时,存根都会为空。但是感谢有关 ws 存根的建议。
    猜你喜欢
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    相关资源
    最近更新 更多