2013-07-02 40 views
3

可以使用模拟对象或不使用模拟对象来测试方法。我喜欢的解决方案,而模拟的时候都没有必要的,因为:用模拟还是不用模拟测试更好?

  1. 他们使测试更加难以理解。
  2. 重构后,修复junit测试是否很痛苦,如果它们是通过模拟实现的。

但是我想问你的意见。

public class OndemandBuilder { 

    .... 
    private LinksBuilder linksBuilder;  
    .... 

    public OndemandBuilder buildLink(String pid) { 

     broadcastOfBuilder = new LinksBuilder(pipsBeanFactory); 
     broadcastOfBuilder.type(XXX).pid(pid); 
     return this; 

    } 

测试与嘲笑:这里测试方法

@Test 
public void testbuildLink() throws Exception { 

    String type = "XXX"; 
    String pid = "test_pid"; 

    LinksBuilder linkBuilder = mock(LinksBuilder.class); 
    given(linkBuilder.type(type)).willReturn(linkBuilder); 

    //builderFactory replace the new call in order to mock it 
    given(builderFactory.createLinksBuilder(pipsBeanFactory)).willReturn(linkBuilder); 

    OndemandBuilder returnedBuilder = builder.buildLink(pid); 

    assertEquals(builder, returnedBuilder); //they point to the same obj 
    verify(linkBuilder, times(1)).type(type); 
    verify(linkBuilder, times(1)).pid(pid); 
    verifyNoMoreInteractions(linkBuilder); 
} 

方法中的returnedBuilder OBJ buildLink是“这个”这意味着,因为它们指向建设者和returnedBuilder不能是不同的内存中的相同对象,所以assertEquals并不真正测试它是否包含由buildLink方法(这是pid)设置的期望字段。

我已经改变了测试,如下所示,不使用模拟。下面的测试声明我们要测试的是哪个构建器包含的LinkBuilder不为null,并且LinkBuilder pid是预期的。

@Test 
public void testbuildLink() throws Exception { 
    String pid = "test_pid"; 

    OndemandBuilder returnedBuilder = builder.buildLink(pid); 

    assertNotNull(returnedBuilder.getLinkBuilder()); 
    assertEquals(pid, returnedBuilder.getLinkBuilder().getPid()); 
} 

我不会用假除非他们是必要的,但我不知道这是有道理,还是我误解了测试的模拟方式。

回答

0

这一切都取决于您通过UNIT测试了解的内容。

因为当你试图单元测试一个类时,这意味着你并不担心底层系统/接口。你假设他们工作正常,因此你只是嘲笑他们。当我说你是ASSUMING意味着你单独测试底层接口。

因此,当你在没有模拟的情况下编写你的JUnits时,你基本上正在进行一个系统或一个集成测试。

但是要回答你的问题,两种方式都有其优点/缺点,理想情况下系统应该都有。

1

在编写单元测试时,在一个坚果壳中你有类之间的依赖关系,并且你想测试一个依赖另一个类的类时,Mocking是一个非常强大的工具,你可以使用模拟对象来限制测试的范围以便您只测试要测试的类中的代码,而不测试它依赖的那些类。我没有进一步解释,我强烈建议您阅读辉煌的Martin Fowler作品Mocks Aren't Stubs,以获得有关该主题的完整介绍。

在你的例子中,没有模拟的测试绝对是更清晰的,但你会注意到你的测试在OndemandBuilderLinksBuilder这两个类中都有代码。这可能是你想要做的,但是这里的'问题'是,如果测试失败了,这可能是由于这两个类中的任何一个的问题。在你的情况下,因为OndemandBuilder.buildLink中的代码是最小的,我会说你的方法是好的。但是,如果此函数中的逻辑更加复杂,那么我建议您想要以不依赖于LinksBuilder.type方法的行为的方式对此方法进行单元测试。这是模拟对象可以帮助你的地方。

假设我们想要测试OndemandBuilder.buildLink独立于LinksBuilder实施。为此,我们希望能够用模拟对象替换中的linksBuilder对象 - 通过这样做,我们可以精确地控制调用此模拟对象返回的内容,从而打破对LinksBuilder实现的依赖。这是该技术Dependency Injection可以帮助您 - 下面的例子展示了我们如何可以修改OndemandBuilder允许linksBuilder与模拟对象来代替(通过注射在构造函数依赖):现在

public class OndemandBuilder { 

    .... 
    private LinksBuilder linksBuilder;  
    .... 

    public class OndemandBuilder(LinksBuilder linksBuilder) { 
     this.linksBuilder = linksBuilder; 
    } 

    public OndemandBuilder buildLink(String pid) { 

     broadcastOfBuilder = new LinksBuilder(pipsBeanFactory); 
     broadcastOfBuilder.type(XXX).pid(pid); 
     return this; 

    } 
} 

,在测试,当您创建OndemandBuilder对象时,可以创建LinksBuilder的模拟版本,将其传递给构造函数,并控制它的行为如何用于测试。通过使用模拟对象和依赖注入,您现在可以正确地单独测试OndemandBuilder,而不受LinksBuilder实现的影响。

希望这会有所帮助。