首页 > 解决方案 > 如何干净地对控制流方法进行单元测试

问题描述

我有一个验证方法,如果在保存记录后应该跳过回调,则返回 true,否则返回 false。

如果窗帘条件为真,则该方法很复杂,有多个返回语句。我不知道如何干净地测试该方法并确认每个测试都在测试不同的条件。

我正在使用 Rails 和 Minitest,但相信这是一个关于单元测试的一般问题,可能适用于其他语言和/或测试框架。

我尝试过测试该方法,结果一团糟。

每个测试都需要更多的设置,我无法证明它们不是在同一行上都返回 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

应该如何测试这样的方法?我正在尝试编写可读、独立和真实的良好单元测试,所以如果我评论返回,正确的测试应该会失败。

标签: rubyunit-testingminitest

解决方案


查看您的代码示例,我看到了两种可能的方法来解决您的测试问题,它们也可以组合使用。

首先,您可以使用 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将产生预期的输出falsefor skip_callback。第二个测试用例将上述输入值与self.attribute_a_changed?存在相结合,false并导致预期输出truefor skip_callback。进行这两个测试将使您确定您确实已经检查了self.attribute_a_changed?对输出的影响。

MC/DC 在此Wikipedia 页面中进行了描述,该页面还具有来自 NASA 的本教程的链接。还有一些关于 SO 的例子,例如这里

其次,您可以通过针对代码的修改版本(突变)运行它们来检查您的测试用例。这称为突变测试,用于判断测试套件的质量。要查看您的一个测试是否真的发现了一个特殊的错误(例如,self.attribute_a_changed?它对结果没有预期的影响),只需插入该错误并查看测试是否失败。例如,您可以简单地self.attribute_a_changed?从代码中删除并查看您的测试是否注意到。或者,您可以将其反转为self.attribute_a_changed? == false并查看您的测试是否发现了该错误。


推荐阅读