如何编写和inheritanceActionController :: 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 

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

 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 

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

 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 ' =================================================================================================== 

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

我终于明白这一点 – 一旦我意识到这是一个普通的Ruby Test :: Unit问题而不是Rails测试问题,快速谷歌立刻透露我如何在Ruby中inheritance抽象unit testing? 已经有了一个很好的答案。 然后唯一缺少的部分是能够使用语法糖:

 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 

该模块将test定义为类方法 ( 这就是为什么需要extend而不是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,但我还不太清楚它还不确定。