微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ruby-on-rails – 如何编写和继承ActionController :: TestCase的抽象子类

我有一堆Rails 3.1控制器,它们都有非常相似的测试要求.我已经提取出公共代码(所有Test :: Unit样式),例如以下三个测试完全可以在所有测试中重复使用:

def create
    new_record    = { field_to_update => new_value }
    create_params = { :commit => "Create",:record => new_record }
    post :create,create_params
  end

  test "should_not_create_without_login" do
    assert_no_difference(count_code) do create; end
    assert_need_to_log_in
  end

  test "should_not_create_without_admin_login" do
    login_as_non_admin
    assert_no_difference(count_code) do create; end
    assert_needs_admin_login
  end

  test "should_create" do
    login_as_admin
    assert_difference(count_code) do create; end
    assert_redirected_to list_path
  end

我打算将它放在一个继承自ActionController :: TestCase的抽象类中.然后每个功能测试只需要覆盖抽象方法,结果令人满意地小而干净,例如,

class Admin::AvailabilitiesControllerTest < Admin::StandardControllerTest
  tests Admin::AvailabilitiesController

  def model          ; Availability              end
  def id_to_change   ; availabilities(:maybe).id end
  def field_to_update; :value                    end
  def new_value      ; 'maybe2'                  end
  def list_path      ; admin_availabilities_path end
end

但是,当我尝试这个时,框架似乎试图直接从抽象类而不是从继承的类运行测试方法

E                                                           
===================================================================================================
Error:                                                      
test_should_not_create_without_login(Admin::ControllerTestBase):
NoMethodError: undefined method `model' for test_should_not_create_without_login(Admin::ControllerTestBase):Admin::ControllerTestBase
    test/lib/admin_controller_test_base.rb:7:in `count_code'
    test/lib/admin_controller_test_base.rb:68:in `block in <class:ControllerTestBase>'
===================================================================================================

我听说其他测试框架和宝石可以为测试的元编程提供机制,所以也许我会以完全错误的方式解决这个问题.但是我已经尝试了几件事并且看了RSpec,coulda,shoulda,context,contest ……我仍然看不到实现我追求的方法.有任何想法吗?谢谢!

解决方法

我终于搞清楚了 – 一旦我意识到这是一个普通的Ruby Test :: Unit问题而不是Rails测试问题,快速谷歌立刻透露 How do I inherit abstract unit tests in Ruby?已经有了一个很好的答案.然后唯一缺少的部分是能够使用语法糖:

test "something should behave in a certain way" do
    ...
end

而不是

def test_something_should_behave_in_a_certain_way" do
    ...
end

我在ActiveSupport代码库本身中找到了这个答案,在lib/active_support/test_case.rb下:

extend ActiveSupport::Testing::Declarative

该模块defines test as a class method(which is why extend is required rather than include).

所以完整的解决方案如下所示:

# tests/functional/admin/availabilities_controller_test.rb

class Admin::AvailabilitiesControllerTest < ActionController::TestCase
  tests Admin::AvailabilitiesController
  include Admin::ControllerTests

  # non-reusable tests and helper methods specific to this 
  # controller test go here
end


# lib/admin/controller_tests.rb

module Admin::ControllerTests
  extend ActiveSupport::Testing::Declarative

  test "this test can be reused by anything which includes this module" do
    ...
  end
end

这种基于模块的方法的缺点是您无法覆盖包含的测试.我猜这只是Test :: Unit的一个基本限制 – 也许最好的答案是转到RSpec,但我还不太清楚它还不确定.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐