分层Java Rest应用程序的单元测试策略

时间:2016-08-01 15:47:55

标签: java rest unit-testing junit mocking

我目前对于我应该做单位测试的正确方法感到困惑。假设我们必须为由这些“公共层”组成的基本Java Rest CRUD应用程序编写 JUnit 测试,其中每个层调用子层:

  • 控制器层(例如:AccountRestController.getAccount(id) - 返回 账户JSON)
  • 服务层:(例如:AccountServive.getAccount(id) - 返回帐户 对象)
  • 存储库层(例如:AccountRepository.getAccount(Id) - 返回 帐户对象)
  • 域层(例如:帐户(id,名称))
  • 数据库表(例如:帐户(ID,NAME))

我们还会对单元测试有以下假设(或限制)(不确定它们是否合适?)

  • 他们必须离开容器(没有Tomcat \ Jetty而且没有内存 数据库 - 我想我会在我的集成测试中这样做)
  • 使用模拟(例如Mockito框架)

所以我的问题是:

  • 最好的方式\正确的方式\写出单位的最佳做法 测试这类应用程序?
  • 要严谨,我们是否必须对每一层进行单元测试(控制器, 服务,存储库,域)每次通过模拟独立 子图层
  • 仅对顶级Rest Controller进行单元测试是否足够?
  • ......再次......我的假设是否恰当? (我们不能这样做 用容器进行单元测试&在内存数据库?)

此致

1 个答案:

答案 0 :(得分:2)

我会直接进入自以为是的水域......

我开始从底层开始编写测试,然后向上,让上层调用真实的东西(只要它很好地包含在我的代码中和/或易于预测正确的行为)下层)。虽然这更像是集成测试,但它对我有用。

对我而言,关于"单元测试的关键部分"是不是每个这些定义都有正确的单元测试,但要进行自动化测试,运行速度足够快(通常我在C ++中将它们保持在3s以下,包括编译,在Android + Java中我有巨大的性能问题,因为整个IDE +工具链在大型项目中,通常会导致5秒以上的时间变得非常缓慢,甚至可以通过gradle构建达到20-30秒,而且我只尝试运行非常基本的单元测试,远离我在C ++中所做的工作。我的测试更接近QA集。)

如果它们失败了,应该很容易找出失败的原因。由于我经常把所有层都调到内部,一些基类的失败经常会导致许多失败,但我很难在快速查看中找出原因,所以这并不让我担心。

当涉及文件/数据库时,事情通常变慢,所以我倾向于区分什么是我的"单元测试"什么属于Integration / QA集。对于基本的东西,内存数据库仍然可以做得很好。

我更喜欢这些混蛋测试,因为当我在被测试的代码下面/上面模拟图层时,它让我担心我会"烘烤"进入该测试的预期结果太多,当我模拟错误时缺少错误。另外,嘲笑某些东西往往是额外的工作,所以当测试的运行时间很低时,我很乐意转向"整合"喜欢测试。

在我看过/使用过的Android / Java中:

  • 我非常喜欢Mockito,它在某种程度上符合我对嘲笑的想法。
  • Robolectric(特定于Android)重量很重,所以我使用它很稀疏,但有时它感觉比嘲笑几乎所有东西更合适。
  • Dagger和其他依赖注入库:我无法理解这些,通常它们与我编写单元测试的方式发生冲突,我也看不到使用它们的任何好处,我更喜欢写纯Java中的依赖注入,它在源代码中的行数几乎相同,而源代码是我在几年后读取它时所期望的。
  • 公共汽车/事件图书馆:这些让我很烦恼,我还没有想办法如何彻底,轻松地测试事件驱动的代码,我的测试总是让人感觉太过分,充满假设,加上这些有时很难嘲笑。
如果可能的话,顺便说一句,在开发过程中总是进行单元测试(接近TDD方法)。之后进行单元测试通常会更加痛苦,然后经常设置API(已经被其他部分/项目使用),当你意识到它很难轻易测试时,已经太晚了或者接下来是重构(没有覆盖原始版本的测试,因此容易出错)。

对于Java Rest CRUD应用程序,我觉得大多数API都可以通过所有层进行测试,而不会造成太多性能损失(可能是数据库模拟/注入/内存,其他外部系统以类似的方式解决) 。但是我只用Java做东西,所以我不能直接体验这种情况。