如何编写和继承ActionController :: TestCase的抽象子类 [英] how to write and inherit from an abstract subclass of ActionController::TestCase
问题描述
我有一堆Rails 3.1控制器,它们都具有非常相似的测试要求。我已经提取了通用代码(所有Test :: Unit样式),例如以下三个测试可在所有测试中完全重用:
I have a bunch of Rails 3.1 controllers which all have very similar testing requirements. I have extracted out the common code (all Test::Unit style), e.g. the following three tests are completely reusable across all of them:
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
继承的抽象类。然后,每个功能测试只需要覆盖抽象方法,最终就变得小巧而干净,例如
and I intended that it could go in an abstract class which inherits from ActionController::TestCase
. Then each functional test would only need to override the abstract methods, ending up pleasingly small and clean, e.g.
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
但是,当我尝试此操作时,框架似乎试图直接从抽象类而不是继承的类运行测试方法:
However, when I try this, it appears that the framework tries to run the test methods directly from the abstract class, rather than from the inherited class:
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 ,上下文, contest 。 ..而且我仍然看不到实现我所追求的目标的方法。有任何想法吗?谢谢!
I've heard that other testing frameworks and gems can provide mechanisms for meta-programming of tests, so maybe I'm going about this in entirely the wrong way. But I've tried several things and looked at RSpec, coulda, shoulda, context, contest ... and I still can't see a way to achieve what I'm after. Any ideas? Thanks!
推荐答案
我终于弄明白了-一旦我意识到这是一个通用的Ruby Test :: Unit问题,而不是Rails测试问题,一个快速的Google即时显示我如何继承抽象单元在Ruby中进行测试?已经有了很好的答案。然后,唯一缺少的部分是能够使用语法糖:
I finally figured this out - once I realised that this is a general Ruby Test::Unit issue rather a Rails testing issue, a quick google instantly revealed How do I inherit abstract unit tests in Ruby? which already had a good answer. Then the only missing piece was being able to use the syntactic sugar:
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
:
I found the answer to this within the ActiveSupport codebase itself, under lib/active_support/test_case.rb
:
extend ActiveSupport::Testing::Declarative
此模块将 test
定义为类方法(这就是为什么需要 extend
而不是 include
的原因。
This module defines test
as a class method (which is why extend
is required rather than include
).
因此完整的解决方案如下:
So the complete solution looks like this:
# 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,但我不确定它是否足够。
The downside of this module-based approach is that you can't override the included tests. I guess that's just a fundamental limitation of Test::Unit - maybe the best answer is to move to RSpec, but I don't know it well enough yet to be sure.
这篇关于如何编写和继承ActionController :: TestCase的抽象子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!