gpt4 book ai didi

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

转载 作者:数据小太阳 更新时间:2023-10-29 07:34:44 24 4
gpt4 key购买 nike

我有一堆 Rails 3.1 Controller ,它们都有非常相似的测试要求。我已经提取出通用代码(所有 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>'
===================================================================================================

我听说其他测试框架和 gem 可以为测试的元编程提供机制,所以我可能以完全错误的方式解决这个问题。但我已经尝试了几件事并查看了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,但我对它的了解还不够深,无法确定。

关于ruby-on-rails - 如何编写和继承 ActionController::TestCase 的抽象子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8888614/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com