【问题标题】:How should you write junit test cases for multiple implementation of the same interface?您应该如何为同一接口的多个实现编写 junit 测试用例?
【发布时间】:2009-01-09 11:32:33
【问题描述】:

在提问之前,让我解释一下当前的设置:

我有一个服务接口,比如Service,和一个实现,比如ServiceImpl。这个 ServiceImpl 使用了一些其他的服务。所有的服务都被spring加载为bean。

现在,我想为 ServiceImpl 编写 junit 测试用例。同样,我使用 applicationContext 来获取 Service bean,然后在其上调用不同的方法来测试它们。

对于公共方法来说,一切看起来都很好,但我如何为私有方法编写测试用例?因为对于不同的实现,我们可能没有相同的私有方法?

任何人都可以在这里帮助我了解编写测试用例的首选方式吗?

【问题讨论】:

标签: java unit-testing junit


【解决方案1】:

纯粹的答案是私有方法被称为是有原因的! ;-)

转过头来:只给出一个(可公开访问的)接口的规范,在编写代码之前,您将如何布置您的测试计划?该接口描述了实现它的对象的预期行为;如果在该级别上无法测试,则说明设计有问题。

例如,如果我们是一家运输公司,我们可能有这些(伪编码)接口:

CapitalAsset {
    Money getPurchaseCost();
    Money getCurrentValue();
    Date  whenPurchased();
    ...
}

PeopleMover {
    Weight getVehicleWeight();
    int    getPersonCapacitly();
    int    getMilesOnFullTank();
    Money  getCostPerPersonMileFullyLoaded(Money fuelPerGallon);
    ...
}

并且可能有包括这些的类:

Bus implements CapitalAsset, PeopleMover {
    Account getCurrentAdvertiser() {...}
    boolean getArticulated() {...}
    ...
}

Computer implements CapitalAsset {
    boolean isRacked() {...}
    ...
}

Van implements CapitalAsset, PeopleMover {
    boolean getWheelchairEnabled() {...}
    ...
}

在设计CapitalAsset 概念和界面时,我们应该与财务人员就CapitalAsset任何 实例的行为方式达成一致。我们将针对CapitalAsset 编写测试,依赖于该协议;我们应该能够在BusComputerVan 上运行这些测试,而不依赖于涉及哪个具体类。 PeopleMover 也是如此。

如果我们需要测试独立于CapitalAssetPeopleMover 通用合同的Bus 的某些内容,那么我们需要单独的总线测试。

如果特定的具体类具有如此复杂的公共方法,以至于 TDD 和/或 BDD 无法清晰地表达其预期行为,那么,这又是一个错误的线索。如果具体类中有私有的“帮助”方法,它们应该是有特定原因的;应该可以问“如果这个助手有缺陷,什么公共行为会受到影响(以及如何)?”

对于合法的、固有的复杂性(即来自问题域),一个类可能适合拥有负责特定概念的帮助器的私有实例。在这种情况下,辅助类应该是可独立测试的。

一个好的经验法则是:

如果测试太复杂,那就太复杂了!

【讨论】:

    【解决方案2】:

    私有方法应该通过类的公共接口来执行。如果你有同一个接口的多个实现,我会为每个实现编写测试类。

    【讨论】:

      【解决方案3】:

      您已经编写了一个接口的多个实现,并希望使用相同的 JUnit4-test 测试所有实现。在下文中,您将看到如何做到这一点。

      还有一个示例说明如何为每个测试用例获取一个新实例。

      示例代码 在我开始解释之前,这里有一些 java.util.list 接口的示例代码:

      public class ListTest {
      
        private List<Integer> list;
      
          public ListTest(List<Integer> list){
            this.list = list;
          }
      
          @Parameters
          public static Collection<Object[]> getParameters() {
            return Arrays.asList(new Object[][] {
              { new ArrayList<Integer>() },
              { new LinkedList<Integer>()}
            });
          }
      
          @Test
          public void addTest(){
            list.add(3);
            assertEquals(1, list.size());
          }
      }
      

      【讨论】:

        【解决方案4】:

        我认为你应该拆分测试用例。

        首先你测试调用不同接口实现的类。这意味着您正在测试公共方法。

        在此之后,您在另一个测试用例中测试接口实现类。他们可以通过反射调用方法。

        【讨论】:

          【解决方案5】:

          我在http://www.artima.com/suiterunner/privateP.html发现了一篇关于如何使用 JUNIT 测试私有方法的有趣文章

          所以,我认为我们应该更喜欢通过测试公共方法来间接测试私有方法。只有在特殊情况下,我们才应该考虑测试私有方法。

          【讨论】:

          • 那篇文章可怕。方法 1 是唯一有效的答案 - 但不知何故,作者坚持认为他同意不测试私有方法的建议,但无论如何都会这样做。要么他的实用方法应该移到它们自己的类中并公开,要么通过现有的类测试进行测试。
          • @dtsazza:我同意方法 1 可能是最好的方法。但是,您应该感谢作者尝试不同的方法并为此写出一篇好文章。此外,通过这样做,他证明了方法 1 可能是最好的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多