首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Rails 4中测试Controller关注点

如何在Rails 4中测试Controller关注点
EN

Stack Overflow用户
提问于 2014-02-26 23:34:12
回答 4查看 23K关注 0票数 48

在Rails 4控制器中使用时,处理关注点测试的最佳方法是什么?假设我有一个琐碎的问题,Citations

代码语言:javascript
复制
module Citations
    extend ActiveSupport::Concern
    def citations ; end
end

所测试的预期行为是,任何包含此关注点的控制器都将得到这个citations端点。

代码语言:javascript
复制
class ConversationController < ActionController::Base
    include Citations
end

很简单。

代码语言:javascript
复制
ConversationController.new.respond_to? :yelling #=> true

但是,有什么正确的方法来孤立地测试这种担忧呢?

代码语言:javascript
复制
class CitationConcernController < ActionController::Base
    include Citations
end

describe CitationConcernController, type: :controller do
    it 'should add the citations endpoint' do
        get :citations
        expect(response).to be_successful
    end
end

不幸的是,这是失败的。

代码语言:javascript
复制
CitationConcernController
  should add the citations endpoint (FAILED - 1)

Failures:

  1) CitationConcernController should add the citations endpoint
     Failure/Error: get :citations
     ActionController::UrlGenerationError:
       No route matches {:controller=>"citation_concern", :action=>"citations"}
     # ./controller_concern_spec.rb:14:in `block (2 levels) in <top (required)>'

这是一个人为的例子。在我的应用程序中,我得到了一个不同的错误。

代码语言:javascript
复制
RuntimeError:
  @routes is nil: make sure you set it in your test's setup method.
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-02-27 03:49:53

您将发现许多建议,建议您使用共享示例并在包含的控制器范围内运行它们。

我个人觉得这太过分了,我更愿意孤立地执行单元测试,然后使用集成测试来确认我的控制器的行为。

方法1:没有路由或响应测试

创建一个假控制器并测试其方法:

代码语言:javascript
复制
describe MyControllerConcern do
  before do
    class FakesController < ApplicationController
      include MyControllerConcern
    end
  end

  after do
    Object.send :remove_const, :FakesController 
  end

  let(:object) { FakesController.new }

  it 'my_method_to_test' do
    expect(object).to eq('expected result')
  end

end

方法2:测试响应

当您的关注点包含路由或需要测试响应、呈现等时.您需要使用匿名控制器运行您的测试。这允许您访问所有与控制器相关的rspec方法和帮助程序:

代码语言:javascript
复制
describe MyControllerConcern, type: :controller do
  controller(ApplicationController) do
    include MyControllerConcern

    def fake_action; redirect_to '/an_url'; end
  end

  before do
    routes.draw {
      get 'fake_action' => 'anonymous#fake_action'
    }
  end
    
  describe 'my_method_to_test' do
    before do
      get :fake_action 
    end

    it do
      expect(response).to redirect_to('/an_url') 
    end
  end
end

如您所见,我们使用controller(ApplicationController)定义匿名控制器。如果您的测试涉及的是ApplicationController以外的其他类,则需要对此进行调整。

此外,要使其正常工作,必须在spec_helper.rb文件中配置以下内容:

代码语言:javascript
复制
config.infer_base_class_for_anonymous_controllers = true

注意:继续测试您所关心的问题是否包括

测试您的关注点类是否包含在目标类中也很重要,有一行就足够了:

代码语言:javascript
复制
describe SomeTargetedController do
  it 'includes MyControllerConcern' do
    expect(SomeTargetedController.ancestors.include? MyControllerConcern).to be(true) 
  end
end
票数 96
EN

Stack Overflow用户

发布于 2015-06-05 13:59:02

从投票最多的答案中简化方法2。

我更喜欢在rspec http://www.relishapp.com/rspec/rspec-rails/docs/controller-specs/anonymous-controller中支持的anonymous controller

你将这样做:

代码语言:javascript
复制
describe ApplicationController, type: :controller do
  controller do
    include MyControllerConcern

    def index; end
  end

  describe 'GET index' do
    it 'will work' do
      get :index
    end
  end
end

请注意,您需要描述ApplicationController并设置类型,以防这种情况在默认情况下发生。

票数 29
EN

Stack Overflow用户

发布于 2016-07-29 21:44:29

我的答案可能比“Benj”和“Calin”的答案要复杂一些,但它有其优点。

代码语言:javascript
复制
describe Concerns::MyConcern, type: :controller do

  described_class.tap do |mod|
    controller(ActionController::Base) { include mod }
  end

  # your tests go here
end

首先,我建议使用匿名控制器,它是ActionController::Base的子类,而不是ApplicationController,也不是应用程序中定义的任何其他基本控制器。通过这种方式,您可以在与任何控制器隔离的情况下测试关注点。如果希望在基本控制器中定义某些方法,只需对它们进行存根。

此外,避免重新键入关注模块名是一个好主意,因为它有助于避免复制粘贴错误。不幸的是,在传递给described_class的块中无法访问controller(ActionController::Base),因此我使用#tap方法创建另一个绑定,该绑定将described_class存储在局部变量中。在使用版本化的API时,这一点特别重要。在这种情况下,在创建一个新版本时复制大量控制器是很常见的,并且非常容易犯这样一个微妙的复制粘贴错误。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22055889

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档