如何模拟100%的复查表达式覆盖率?

时间:2018-09-21 18:55:56

标签: ruby testing code-coverage

我有一些代码,其中有两次检查零价格的方法(例如)。 如果第一个检查失败,第二个检查将不会到达队列,还是不会? 如何创建可以覆盖此代码100%的测试?

def products
  # first check on zero price
  products = database.query 'SELECT * FROM product WHERE price > 0;'
  products.map do |product|

    # second check on zero price
    unless product[:price] > 0
      warn 'wrong price'
      next
    end

    # some operation under product
  end
end

1 个答案:

答案 0 :(得分:0)

真正的100%覆盖率实际上是不现实的。除非您的代码非常独立并且定义良好,否则证明program correctness基本上是不可能的。

这依赖于一个数据库,该数据库可能存在错误,CPU可能发生故障,内存可能不可靠,磁盘可能发生故障,文件系统可能已损坏等等。但是,在进行测试时,您不能将这些因素考虑在内,对于罕见的随机事件进行测试几乎始终是毫无根据的妄想症。

想象以下代码:

def return_items(items)
  items.each do |item|
    if (world_about_to_be_hit_by_asteroid?)
      warn "World about to be destroyed, may not be able to process this refund in time!"
    end

    item.return_to_inventory!

    if (item.could_not_be_returned_due_to_zombie_outbreak?)
      item.cancel_return!
      warn "The living dead are now taking over, return cancelled."
    end

    item.estimate_shipping unless (Alerts.speed_of_light_changed?)

    if (sun_about_to_explode?)
      warn "Head to shelter immediately."
    end
  end
end

相反,请尝试覆盖您在必要的条件下可以合理测试的100%功能。在这种情况下,您是否正在测试数据库查询产生正确的结果?您是否正在测试数据库驱动程序返回数据?您是否正在针对具有多种价格(例如-1、0和1)的数据集进行测试,以确保仅获得一条正确的记录?

像这样在生产代码中间放置warn是一个非常不好的习惯,应该避免。在开发过程中,如果违反某些条件,您可能会有类似“断言”的语句故意使程序崩溃,但是这些语句仅应保留给最严重的情况,否则可能会导致灾难性的后果。

这里的问题是该方法不仅过于偏执,这是锡纸帽子编码,但无法传达其作用。更好的方法:

def products(above_price: 0)
  database.query('SELECT * FROM product WHERE price > ?', above_price)
end

您有信心的地方database.query会起作用,因为该代码已在其他地方进行了测试,例如在数据库驱动程序的测试套件中。您可以像这样测试与之的互动:

# Create products at prices -1, 0, 1 and 100

assert_equal 2, products.length
assert_equal 1, products(above_price: 20).length
assert_equal 4, products(above_price: -100).length

您可以在此处进行更详细的测试,以确保返回正确的产品,而不仅仅是返回一些随机产品的正确数量。