何时/如何对CRUD应用程序进行单元测试?

33

最近我听到了很多关于单元测试的事情。

我想弄清楚的是,如何进行单元测试,或者说在业务较为糟糕的应用程序中是否应该进行单元测试(基本上是一个从数据库中读取/写入数据的应用程序)。

在这种情况下,单元测试是否值得投入精力,还是你通常会对更复杂的东西进行单元测试呢?

谢谢!


从这些回复中我所理解的是,我不应该对数据库读写进行单元测试,而应该测试业务逻辑代码。 - Shai UI
1
测试所有可能出错的地方。这是常识。 - Yauheni Sivukha
8个回答

21

单元测试是关于测试离散的代码单元——仅限于一个方法。

当你涉及到CRUD(增删改查)时,你需要测试网络、IO、数据库和其他事物,这超出了单元测试的范畴。在这种情况下,这被称为集成测试(你正在测试你的代码如何与其他代码/系统集成)。

在任何软件项目中,无论是CRUD应用程序还是其他类型的应用程序,都需要进行这两种类型的测试(以及其他类型的测试——回归、性能等)。


4
单元测试可以测试不同的系统受测对象(SUT):两种方法或甚至一些类。单元测试之间的区别非常模糊,对于单元测试和集成测试中SUT的大小和属性没有清晰的定义。 - Yauheni Sivukha
@Yauheni Sivukha - 来自维基百科:一个单元是应用程序中最小的可测试部分。http://en.wikipedia.org/wiki/Unit_testing - Oded
@Odded - 维基百科并没有说最小可测试部分是方法。这取决于上下文。如果测试按顺序验证总数,则应填写订单行。顺便说一下:https://dev59.com/cnVD5IYBdhLWcg3wWKLc - Yauheni Sivukha
根据测试金字塔,集成测试仅占应用程序的一小部分。因此,您是否建议“仅限CRUD”的应用程序只需具有较小的代码覆盖率? - BornToCode
看看OP的问题 - “一个糟糕的商业应用程序(基本上是一个将数据写入/从数据库读取数据的应用程序)” - 没有真正的业务逻辑。 - BornToCode
显示剩余3条评论

16
如果你的应用程序只是进行CRUD操作,那么单元测试没有意义。但是,如果有任何一种业务逻辑在从数据库中获取值时对其进行操作或在将其输入之前验证它们,则构建单元测试是一个好主意。在我看来,测试CRUD部分不属于单元测试。

1
我们有大量的CRUD,每当有人在同一个控制器或任何一个扩展基类中推送损坏的代码时,它就会崩溃。集成测试可以在QA或更糟糕的实际用户之前捕获它。在我看来,集成测试非常有用。 - zeros-and-ones

8
我知道很多人都强调应该采用测试驱动的设计方法,但我倾向于为更复杂的事物编写单元测试。
我的经验法则是,对于我真正预计会经常出现问题或者我不会立即注意到其存在问题的事物,我构建自动化测试。最重要的是,我希望它可以测试那些我不能或者不愿意彻底重新测试的事物。
例如,“使用47个不同变量计算一些大而复杂的东西”的模块应该有一堆测试来实现良好的代码覆盖率,应该覆盖所有可能的代码路径,但实际将结果保存回数据库的代码并不一定需要测试,特别是如果它只是进行简单的CRUD操作。
此外,我喜欢使用自动化UI测试(使用WatiN或类似工具)为我的网站编写回归测试,以便在更改某些核心组件时运行一个健全性检查,以确保我没有破坏站点中的一些小角落。
最终,这一切都关乎投资回报率。你花了多少时间和精力,得到了多少回报。如果您的单元测试已经接近100%的代码覆盖率,但仅限于您的CRUD企业应用程序的数据访问层,那么您正在浪费时间和雇主的金钱,简而言之。但是,如果您正在构建火箭或医疗设备,或者如果您只是一个由两个人组成的团队,没有QA部门的资源,那么大量的单元测试可以为您节省大量的时间,金钱和/或生命。

3
"Test-first" 不是关于单元测试的,它是一种名为 TDD(或某些人称之为 BDD)的设计方法论。 - Oded

6

糟糕的应用很少会一直保持糟糕。它们最终会发展成一个业务对象层。

因此,是的,我会进行单元测试。即使是基本的糟糕应用也应该被拆分为交互层、数据访问层和非常简单的UI(请注意,所有UI状态都应该保存在交互层中)。最终,您可能会在交互和数据访问层之间获得一个业务对象层。


4

测试所有可能出错的情况

当然,如果你有一个面向数据的应用程序,你需要测试你的CRUD操作。根据我的经验,这种测试非常有用,因为它们可以捕捉到映射、存储过程逻辑、数据模型错误、错误数据等方面的许多错误。


1

单元测试是关于测试小而简单的功能模块。通常,您会对应用程序的数据层进行单元测试,该层将处理所有CRUD功能。创建和检索的测试可能如下所示:

    PrimaryKey = InsertObject(TestObject)

    if PrimaryKey = 0 then

     AssertTestFailed("Primary Key Not Returned.")

    end if


    NewInstanceOfObject = GetObject(PrimaryKey)

    If NewInstanceOfObject <> TestObject then
      AssertTestFailed("Record not located.")
else
      AssertTestPassed("This Code is awesome UnitTest Passed.")
    end if

1

CRUD(Create、Retrieve、Update、Delete)类型的应用很难进行单元测试,正如@oded所写:这些类型的应用通常需要进行集成测试。

但是,如果您正确地分层您的代码,您就可以隔离业务逻辑并对其进行单元测试。

例如,如果您使用“清洁架构”,那么您的API将会分为以下几个部分:

  • 处理器/控制器(这些是由路由组件激活的代码片段)
  • 服务(即业务逻辑组件),它们被注入到处理器中
  • 存储库(负责数据访问),它们被依次注入到服务中。

在这种结构下,您可以轻松地模拟存储库(它们是唯一处理状态的部分)并对服务进行单元测试。

处理器本身不应包含任何逻辑(它们只验证输入、将其传递给服务并显示响应),因此可能不会进行单元测试。

希望这可以帮助您:-)


-1

我相信,如果你使用的ORM已经由社区进行了充分测试,并且遵循了定义良好的模式来实现CRUD操作,那么写单元测试就没有必要了。

但是,如果你使用一些低级别的库与数据库通信,则错误的机会就会增加。在这种情况下,我会编写单元测试来使我的代码更加严谨和防错。编写这些测试并不需要花费很多时间,因为所有类都遵循相同的模式。

网上有大量不同的数据库及其相关的ORM,但移动平台上的选择却有限。这是正确的,因为在移动设备上存储数据并不是一个非常好的想法,但在某些情况下确实需要。在移动平台上编写CRUD时,我会编写单元测试。


1
很抱歉不同意,但ORM只是CRUD操作的一个组成部分。在它周围有数据处理、层遍历(从前端到服务器应用程序)、验证规则等等。因此,是的,您不需要为ORM编写单元测试,但您肯定需要为操作编写集成测试。 - ioannis.th

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接