【问题标题】:Is it possible and/or advisable to generate tests dynamically in rails?是否可以和/或建议在 Rails 中动态生成测试?
【发布时间】:2009-07-16 13:28:14
【问题描述】:

我发现在 Rails 应用程序编程中非常方便的一个技巧是 class_eval 可用于动态创建方法。我现在开始进行测试,我想知道是否可以使用类似的想法来生成测试。

例如,我有一个before_filter 要求用户登录以执行控制器中的所有操作。我想编写测试以确保将before_filter 应用于所有操作。我不想单独写出每个测试,而是自动生成所有这些测试。

这种类型的测试是否可取,还是我应该坚持单独编写测试?如果是的话,怎么做呢?

编辑:这可能看起来像:

actions = {:index => :get,:show => :get,:edit => :get,:update => :put}
actions.each_pair do |action,type|
  class_eval(%Q{def test_user_required_for_#{action}
      set_active_user users(:one)
      #{type} :#{action}
      assert flash[:error]
      assert_redirected_to :action => :index
    end
  })
end

既然人们已经验证这可能有用,我应该将这样的代码块放在哪里,以便它只执行一次来创建这些测试?

【问题讨论】:

  • 尽量不要使用class_eval的字符串形式。如果您必须使用class_eval(通常不需要),请使用块形式。更安全。

标签: ruby-on-rails unit-testing testing


【解决方案1】:

DRY 原则同样适用于测试代码。

使用一种方法来生成所有这些测试应该更容易首先验证测试是否正确。

回答评论(注意:我已经有一段时间没有编写 Rails 测试代码了,所以它可能不是 100% 正确的)。 %| | 之间的所有内容都是一个大字符串:

MyControllerTest

  [:index, :show, :new, :create, :edit, :update, :destroy].each do |action|
      class_eval do %|
        test "#{action} requires before filter" do
          #test #{action} code here
        end
      |
  end

end

【讨论】:

  • 那么如何/在哪里创建这些测试?
  • 你可以把这段代码放在哪里,以便它执行一次并且只执行一次来设置这些测试?
  • 这属于您要测试的任何控制器。例如,如果您想确保 AccountsController 被锁定,代码将放在 accounts_controller_test.rb 文件中。
  • 好的,很好用!我一直在尝试编写一个构造函数并将其放入其中,但是您是对的,您只需将其直接放入类中,而不是单独的方法调用。谢谢!
  • 否决 class_eval 与字符串的使用。 *_eval 在 Ruby 中几乎从不需要使用字符串,因此应避免使用它,因为它不安全。 class_eval 带块要好得多。 (在 RSpec 中,您根本不需要 class_eval。)我也不同意 DRY 既适用于测试代码,也适用于应用程序代码。虽然我尝试删除测试代码中的重复,但我认为测试的可读性更重要,因此我的测试代码的重复阈值高于应用程序代码。
【解决方案2】:

一般来说,单独编写测试。但是,如果您有一堆相同的测试,我认为从 each 块生成每个测试都没有错。

额外提示:使用 RSpec,而不是 Test::Unit。除了总体上更好之外,它还让你做的事情变得更容易。

【讨论】:

  • rspec 与测试单元的易用性在很大程度上取决于个人喜好。我个人认为 test::unit (+ shoulda) 更容易,更“自然”。这是一个 YMMV 主题:)
  • @TarynEast 我不再认为这是一个品味问题:RSpec 的 should 语法鼓励您考虑行为,而 Test::Unit 的 assert 语法鼓励您考虑实现.通常,应该测试的是行为而不是实现,因为我们只对验证 interface 是否按预期工作感兴趣。如果您发现 Test::Unit 更自然,那可能意味着您正在尝试测试实现——也就是说,您正在尝试测试错误的东西。
  • @TarynEast 我刚刚重读并注意到您使用的是Shouda,因此您会得到一些should 语法。那么,为什么不直接使用 RSpec 呢?你更喜欢Shouda的哪一点?
  • 能够将新断言定义为简单的新方法,而不必创建全新的匹配器类。
  • @TarynEast 我会看看;有趣的。不过,我不得不承认,在使用 RSpec 将近 5 年后,我上个月才第一次创建了一个自定义匹配器,所以这不是我经常做的事情。我的大部分印象是,虽然 Shoulda 有一些很酷的功能,但它主要是 RSpec 的劣质仿制品。
【解决方案3】:

使用testDSL 时没有理由使用class_eval

class MyControllerTest
  [:index, :show, :new, :create, :edit, :update, :destroy].each do |action|
    test "#{action} requires before filter" do
      #test #{action} code here
    end
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-04
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    相关资源
    最近更新 更多