Junit / Mockito:选择使用模拟或集成测试进行测试

时间:2011-07-05 06:15:58

标签: java junit mockito

我正在学习Mockito。在开始使用模拟对象之前,我有一些单元测试更像集成测试,所以我有一个带有setUpBeforeClass()的测试类,如下所示:

@BeforeClass
public static void setUpBeforeClass() throws Exception {
    instance = new UserDataAccess();
    instance.setDb(new MyDb());
}

现在使用模拟对象非常相似,但设置稍微复杂一些:

@BeforeClass
public static void setupBeforeClass throws Exception {
    instance = new UserDataAccess();
    MyDb myDb = mock(MyDb.class);
    when(...).thenReturn(...);
    ...
    instance.setDb(myDb);
}

此外,我还有一个测试套件,用于在运行测试之前将数据库加载到一个众所周知的状态,这是通过套件调用的第一个测试类完成的。

我在想的是我不应该抛弃集成测试,因此我正在考虑将测试套件拆分为UnitTestSuite和IntegrationTestSuite。事实上,模拟测试并没有测试所有内容,例如他们不测试查询是否正确。

此外,这两个套件之间的唯一区别是初始DB重置和setUpBeforeClass()代码。复制和更改所有测试类只是为了更改方法,这将是一种浪费。初始DB重置很容易跳过,我只是不在单元测试套件中包含db reset测试类。

要拆分单元和集成测试,您的建议是什么?扩展所有原始类以覆盖静态方法,然后在套件中包含正确的类?

还是其他方法?你是怎么做的,或者你会做什么?

2 个答案:

答案 0 :(得分:9)

永远记住单元测试(使用模拟)背后的想法是戳一个类的所有黑暗角落。它们是关于确保该类的行为与您能想到的所有类型的输入一样。这就是为什么我们使用模拟来做这个,因为我们可以编程那些模拟来做各种可能难以重现的事情,如果类被连接到应用程序的其余部分。

另一方面,整合具有不同的侧重点。它是关于确保所有类一起工作以产生所需的结果。因此在编码时请记住这一点。这是你追求的全局。您不必担心单个类的边缘情况,因为这是您的模拟单元测试的工作。但像数据库状态这样的东西正是集成测试很重要的原因。

我同意@stivlo关于在内存数据库工作中使用HSQL等产品的看法。它们既可以加速集成测试,又可以帮助确保测试的已知起点。

我建议将单元测试和集成测试保存在单独的目录中,或者至少将单独的包命名为匹配。很简单,因为它可以帮助您记住您正在处理的内容。

还要注意测试蠕变。 IE浏览器。实例化大量应用程序类的单元测试,实际上应该转移到集成测试,以及在类上进行大量详细变化样式测试的集成测试 - 单元测试的候选者。特别是在最后,如果存在不存在的集成测试,您可以从构建中删除大量时间。

最后,就像任何代码一样,测试代码需要不时得到一点爱和关注。所以请留意重构机会。话虽如此,我也看到了测试代码已经变得难以使用,因为它过于笼统和过度设计。请记住,测试代码不是生产代码,因此在大多数情况下,清晰度远比工程更重要。这是你将通过经验获得的平衡。

答案 1 :(得分:0)

我建议使用内存数据库进行集成测试,而不是模拟对象。

对于单元测试,我假设您使用数据库作为存根来为测试提供一些数据,并在测试调用saveMyDomainObject()之类的时候作为模拟。在第一种情况下,您只能模拟实际需要的特定测试,而不是整个数据库设置。对于第二种情况,您应该使用Mockito的validate来检查预期的行为是否正确。