允许我的Junit测试与真实的数据库进行交互是不好的做法吗?

时间:2018-08-23 06:32:21

标签: java junit flyway

我正在构建基本的HTTP API,并且类似POST /users之类的操作会在数据库中创建新的用户记录。

我知道我可以模拟这些调用,但是在某种程度上,我想知道让Junit测试针对真实(测试)数据库运行是否更容易?这是不好的做法吗?应该只对真实的数据库运行集成测试吗?

我正在使用flyway来维护我的构建的测试架构和Maven,因此我可以让它在每个构建中使用正确的架构来重新创建测试数据库。但是我也担心,在每次测试之间我需要一些额外的开销来维护/清理数据库的状态,而且我不确定是否有这样做的好方法。

5 个答案:

答案 0 :(得分:6)

单元测试用于测试单个代码单元。这意味着您通过编写仅测试方法的内容来编写单元测试。如果存在外部依赖项,则可以模拟它们,而不是实际调用和使用这些依赖项。

因此,如果您编写代码并且该代码与实际数据库进行交互,则它不是单元测试。说,由于某种原因,您对db的调用失败,然后单元测试也将失败。单元测试的成功或失败不应取决于外部依赖关系,例如db。您必须假设数据库调用成功,然后使用某些模拟框架(Mockito)对数据进行硬编码,然后使用该数据测试您的方法。

答案 1 :(得分:2)

通常,这取决于。

在具有大量JUnit测试的大型项目中,性能开销很重要。同样,在数据库中设置测试数据所需的工作时间以及您的测试所需的概念不会干扰其他测试的测试数据,而JUnit测试的并行执行对于仅针对数据库进行测试是一个非常重要的参数如果需要的话,否则将其嘲笑。

在小型项目中,此问题可能更易于处理,因此您始终可以使用数据库,但我个人甚至在小型项目中也不会这样做。

答案 2 :(得分:1)

现代开发实践建议每个开发人员都经常运行全套单元测试。单元测试应该可靠(如果代码正确,则应该失败)使用外部数据库可能会干扰那些desiradata。

  • 如果数据库是共享的,则不同开发人员同时运行测试套件可能会相互干扰。
  • 为每个测试设置和拆除数据库通常很昂贵,因此会使测试太慢而无法频繁执行。

答案 3 :(得分:1)

正如其他几个答案所建议的那样,您应该创建单元测试,以模拟所有外部依赖项来测试小段代码。

但是有时(很多次)应该值得测试整个功能。特别是当您使用诸如Spring之类的框架时。或者您使用很多注释。当您的类或方法具有批注时,通常无法通过单元测试来测试这些批注的效果。您需要在测试过程中运行整个框架,以确保其按预期工作。

在我们当前的项目中,集成测试几乎与单元测试一样多。我们将H2内存数据库用于这些测试,这样就可以避免由于连接问题而导致的失败,并且Spring的测试包可以将多个集成测试收集并运行到同一个测试上下文中,因此它只需构建一次上下文对于多个测试,以这种方式运行这些测试并不太昂贵。

您还可以为项目的不同部分(具有不同的设置和数据库内容)创建单独的测试上下文,这样,在不同上下文下运行的测试就不会互相干扰。

不要害怕使用很多集成测试。无论如何,您都需要一些,如果您已经具有测试上下文,那么在同一个上下文中添加更多测试就没什么大不了的。

在很多情况下,需要花很多精力来进行单元测试(或者根本无法完全涵盖),但可以通过集成测试来简单地覆盖。

个人经历: 从Spring Boot切换到Spring Boot 2时,我们的大量集成测试非常有用。

回到原始问题: 单元测试不应连接到实际的数据库,但可以随意使用更多的集成测试。 (带有内存数据库)

答案 4 :(得分:1)

一个流行的选择是使用内存数据库来运行测试。这样可以轻松测试例如涉及数据库调用的存储库方法和业务逻辑。

选择“真实”数据库时,请确保每个开发人员都有自己的测试数据库,以避免冲突。使用真实数据库的优点是,这可以防止由于内存数据库和真实数据库之间的行为略有不同而引起的可能出现的问题。但是,对实际数据库运行大型测试套件时,测试执行性能可能会成为问题。

某些数据库可以以不需要为测试执行而安装数据库的方式进行嵌入。例如,有一个SO thread关于在Spring Boot测试中启动嵌入式Postgres的问题。