ruby - 如何干净地对控制流方法进行单元测试
问题描述
我有一个验证方法,如果在保存记录后应该跳过回调,则返回 true,否则返回 false。
如果窗帘条件为真,则该方法很复杂,有多个返回语句。我不知道如何干净地测试该方法并确认每个测试都在测试不同的条件。
我正在使用 Rails 和 Minitest,但相信这是一个关于单元测试的一般问题,可能适用于其他语言和/或测试框架。
我尝试过测试该方法,结果一团糟。
- 如果没有更改感兴趣的字段并且不是 bulk_association,则返回 true
- 如果批量关联但没有关联用户,则返回 true
- 如果批量关联和关联的用户,但不是活动的,则返回 true
- 如果批量关联和关联的活动用户返回 false
- 如果 attribute_a 已更改并关联活动用户,则返回 false
- 如果 attribute_b 已更改并关联活动用户,则返回 false
- 如果 attribute_c 已更改并关联活动用户,则返回 false
每个测试都需要更多的设置,我无法证明它们不是在同一行上都返回 true。
def skip_callback
return true unless (self.attribute_a_changed? || self.attribute_b_changed? || self.attribute_c_changed? || self.bulk_association == true)
user = self.user
return true if user.blank?
return true unless user.active
false
end
应该如何测试这样的方法?我正在尝试编写可读、独立和真实的良好单元测试,所以如果我评论返回,正确的测试应该会失败。
解决方案
查看您的代码示例,我看到了两种可能的方法来解决您的测试问题,它们也可以组合使用。
首先,您可以使用 MC/DC(修改后的条件/决策覆盖)来设计您的测试用例。其背后的想法如下:为b
代码的每个布尔输入确定两个具有以下属性的测试用例: a) 一个测试用例具有预期true
结果,另一个具有预期false
结果。b) 两个测试用例具有相同的输入,除了b
,在一个测试用例中具有值,而在另一个测试用例true
中具有值false
。换句话说,在这两个测试用例之间,只有b
改变和控制输出。
示例:对于self.attribute_a_changed?
控制输出的输入,其他输入必须具有以下值:
self.attribute_b_changed?
必须false
self.attribute_c_changed?
必须false
self.bulk_association
必须不同于true
self.user.blank?
必须false
self.user.active
必须true
然后,具有上述所有输入值的一个测试用例与self.attribute_a_changed?
being相结合true
将产生预期的输出false
for skip_callback
。第二个测试用例将上述输入值与self.attribute_a_changed?
存在相结合,false
并导致预期输出true
for skip_callback
。进行这两个测试将使您确定您确实已经检查了self.attribute_a_changed?
对输出的影响。
MC/DC 在此Wikipedia 页面中进行了描述,该页面还具有来自 NASA 的本教程的链接。还有一些关于 SO 的例子,例如这里。
其次,您可以通过针对代码的修改版本(突变)运行它们来检查您的测试用例。这称为突变测试,用于判断测试套件的质量。要查看您的一个测试是否真的发现了一个特殊的错误(例如,self.attribute_a_changed?
它对结果没有预期的影响),只需插入该错误并查看测试是否失败。例如,您可以简单地self.attribute_a_changed?
从代码中删除并查看您的测试是否注意到。或者,您可以将其反转为self.attribute_a_changed? == false
并查看您的测试是否发现了该错误。
推荐阅读
- r - 将社区数据转换为素食套餐的宽格式
- python - 试图创造人工智能 - 一些 IF 语句没有捕捉到
- angularjs - 在 angularjs 控制器中从外部获取 POST 数据
- java - 在 Android 上创建一个同时包含 simple_list_item_1 和 simple_list_item_multiple_choice 的 ListView
- visual-studio - 根据操作系统位数自动启动 32 位/64 位?
- javascript - 与 DOM 首次交互时调用函数(点击桌面浏览器/点击移动浏览器)
- c# - 如何在 ASP 中始终保持会话变量的更新。网络MVC
- python - TypeError: a bytes-like object is required, not 'str' ,我应该怎么做才能修复它?
- php - UID 大于某个值的 imap_search
- javascript - 即使在完成选择后,也会在 react-big-calendar 中突出显示所选插槽的背景