如何编写和继承ActionController :: TestCase的抽象子类 [英] how to write and inherit from an abstract subclass of ActionController::TestCase

查看:100
本文介绍了如何编写和继承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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆