使用内存中的数据库和模拟功能测试DAO和服务层

时间:2018-10-30 15:04:21

标签: java unit-testing testing mocking

在学习Java测试期间,我遇到了一个我没有真正得到的东西。 因此,基本上,我具有DAO的单元测试,其中可以借助内存数据库HSQL测试CRUD操作。
好了,下一步是测试服务层。在网络上,他们说要使用模拟来模拟DAO,然后测试Service。

我只看到一种使用模拟的方法:如果Service中有某些方法,而DAO中不存在这些方法。然后,我们不需要测试CRUD操作(DAO本身),因此我们模拟DAO并仅测试Service。

  1. 但是如果我在Service中使用与DAO中相同的方法怎么办?
  2. 如果我像使用DAO一样仅使用内存数据库来测试Service,该怎么办?

我想知道,使用模拟代替内存数据库有什么好处。而且,我猜想,使用Mocks时可读性较差。

如果有意义的话-我使用Spring。

2 个答案:

答案 0 :(得分:1)

这是一个广泛且可能引起争议的主题……因此请准备好应对各种各样的答案和不同的观点……

内存数据库的优势:

  • 力量 减少了一组集成测试,这些测试旨在确保您避免延迟/明确的加载情况,并确保获得格式正确的实体。
  • 在某些情况下,它 可能 会减少每种测试方法所需的设置代码。例如如果您必须在几个不同的模拟上建立一打模拟调用。
  • 在了解要测试的内容时,有时可能更容易推理出测试内容

内存数据库的缺点:

  • 缺少对单元测试的完全隔离
  • 要求您对DI容器进行初始化以进行单元测试。
  • 根据内存数据库提供者与生产数据库的不同,可能会提供错误的安全感,

模拟的优点:

  • 完全隔离正在测试的代码
  • 可以仅设置支持测试所需的内容。例如不需要配置完整的实体。
  • 测试通常运行得更快,您可以完全忽略用于单元测试的DI框架(隔离的一部分,但值得一提)。

模拟的缺点:

    测试代码可能变得复杂而脆弱,这取决于服务方法的凝聚力以及它们如何与DAO层耦合。即,如果您需要设置20个模拟方法调用和3个模拟对象,那很快就会变得乏味(但是,这应该表明您的服务需要重构)。

要回答第一个问题,您问到两种方法都相同时会发生什么—简单答案。它们不是相同的方法。他们在做两件事。一个正在与数据库进行通信,另一个正在应用业务逻辑。如果您确实有一个传递,则您可能仍应该在服务层中对其进行一次测试,以确保它在您的DAO上调用正确的东西。

无论您采用哪种方式,都不要忘记对代码进行集成测试!

答案 1 :(得分:1)

从经验(已经编写了成千上万的自动化测试)来看:

  1. 尽可能避免进行模拟,因为这不利于进行良好且适当的测试。通常,使用模拟的测试是从错误的角度编写的,即开发人员仅考虑执行实现代码,而不是检查有意义的面向业务的行为。好的测试是根据需求编写的,不仅仅是为了练习代码。

  2. 集成测试可以足够快(真正重要的是开发人员不要被劝阻不要经常运行它们),并且可以使它们在仅回滚的DB事务中运行,从而确保测试隔离。 / p>

  3. 使用您的开发数据库(通常是与生产环境中使用相同数据库引擎的共享远程数据库,在该数据库中也可以手动测试该应用程序),而不要使用内存数据库。这样,您可以避免在每次测试运行时都创建昂贵的内存数据库模式(假设通常情况下,开发数据库始终处于运行状态,并且具有所有表),并且避免了由于使用两种不同的数据库技术而引起的任何潜在问题

以上内容描述了我在Java Web应用程序(使用Java EE或Spring,没关系)中使用的方法,该数据库在关系数据库中具有数百个表(可通过JPA / Hibernate访问)。只有一个容器外集成测试的测试套件,其中每个测试都在单个db事务中运行,该事务始终回滚。一些测试做了一些模拟,特别是对于远程Web服务的调用,仅此而已。