ruby-on-rails - 如何测试在多个条件下过滤的方法?

标签 ruby-on-rails ruby testing rspec

我想改进一种便捷方法的规范,该方法返回一组用户,这些用户的购买将于明天到期,并将使用某种支付方式(忽略其他支付方式)进行支付。

规范大致如下:

it "doesn't return users without purchases being due tomorrow" do
  # create user and associated records that don't fit the time condition
  expect(subject).to eq([])
end

context "with users who have purchases due tomorrow" do

  it "returns users with $CERTAIN_PAYMENT_METHOD" do
    # create different users with different payment methods,
    # all matching the time condition.

    expect(subject).to eq([user_1, user_2])
  end


  it "doesn't return users without $CERTAIN_PAYMENT_METHOD" do
    # create user with credit card,
    # matching the time condition.

    expect(subject).to eq([])
  end

end

我在这里看到三种可能的方法:

  1. 上面使用的方法:设置任意组合的记录,并期望特定于单个条件的事物,始终断言整个数组。设置可能很长且重复。
  2. 设置任意组合,并期望在返回的数组中包含/排除某些内容。这些“软期望”读起来很棒,但也很容易出错。
  3. 设置(几乎)所有记录组合,并有单一期望。这不会产生重叠,但也会让开发人员对为什么此方法返回此特定数组一无所知。

所有方法都有其缺点,我想知道是否有最佳实践来测试这些方法?

最佳答案

在选项 1 和选项 2 之间做出决定可能很棘手,但选项 3 无疑是最糟糕的选项。单元测试有两个目的* - 它们插入干净的代码设计,并记录代码对 future 开发人员的作用。正如您正确指出的那样,进行“一次巨大的测试”会使开发人员不知道该方法为何如此运行,因此破坏了测试的一半好处。此外,这些类型的测试并不是插入干净代码设计的测试,因此您可能也会失去这种好处。

选项 1 或 2 哪个更好取决于您的情况。重复的设置代码不一定是问题(研究 DAMP 与 DRY 相对于 TDD),如果这是一个问题,它可以通过提取通用设置代码来改进,以便它可以在测试用例之间共享(尽管这可能是一种气味如果走得太远)。无论如何,我看不出选项 2 如何解决重复设置代码的问题 - 两个选项之间的唯一区别在于您如何进行断言。

“标准”与“弱”断言的问题是一个共同的主题(研究严格模拟与松散模拟)并且是选项 1 和 2 之间的主要区别。选项 1 的问题是对生产代码进行 1 次更改可能导致必须更改每个测试用例的断言。出于这个原因,我建议对整个数组进行一些断言测试(以测试顺序和完整性等),但对于大多数测试来说,尽可能具体并且只测试包含/排除。这允许测试清楚地记录哪些类型的设置导致哪些输出值,而不是每个测试都有一长串断言,只有其中一个对当前测试用例感兴趣。

指导原则是,不要对同一事物进行两次测试。如果通过断言每个测试中的每个元素,您觉得自己正在测试同一件事两次,那么这可能不是正确的方法。

* 好吧,有时他们也会发现错误,但他们自己并不会告诉您您的系统可以正常工作并且没有错误。这就是测试整个系统的其他测试形式的目的。绿色单元测试无法让您有足够的信心将产品发布。

关于ruby-on-rails - 如何测试在多个条件下过滤的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39872271/

相关文章:

ruby-on-rails - Omniauth - Facebook 应用程序在 Facebook 身份验证成功后不运行回调 url

ruby-on-rails - Heroku on Rails - 无效的 DATABASE_URL

ruby-on-rails - Ruby datetime 属性值未保存在 SQLite DB 中

javascript - 混淆模拟无状态 React 组件辅助函数与 sinon、enyzme 和 ES6 导入

django - **finally :* clause? 的语法错误在哪里

unit-testing - 在 BDD 中测试应用程序状态

ruby-on-rails - 对 Rails 4/Postgres 的 schema.rb 中的列重新排序是否安全?

javascript - Turbolinks Rails 5 切换事件不起作用

ruby-on-rails - UnInitialized Contant Twitter::Grape 使用 grape 示例代码

ruby-on-rails - Rails 4 在单独的 Controller 中搜索多个模型