如何在 Rails 4 中测试控制器关注点 [英] How to test a Controller Concern in Rails 4

查看:21
本文介绍了如何在 Rails 4 中测试控制器关注点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What is the best way to handle testing of concerns when used in Rails 4 controllers? Say I have a trivial concern Citations.

module Citations
    extend ActiveSupport::Concern
    def citations ; end
end

测试中的预期行为是任何包含此问题的控制器都会获得此 citations 端点.

The expected behavior under test is that any controller which includes this concern would get this citations endpoint.

class ConversationController < ActionController::Base
    include Citations
end

简单.

ConversationController.new.respond_to? :yelling #=> true

但是孤立地测试这个问题的正确方法是什么?

But what is the right way to test this concern in isolation?

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

不幸的是,这失败了.

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

这是一个人为的例子.在我的应用中,我收到了不同的错误.

This is a contrived example. In my app, I get a different error.

RuntimeError:
  @routes is nil: make sure you set it in your test's setup method.

推荐答案

您会发现很多建议告诉您使用共享示例并在您包含的控制器范围内运行它们.

You will find many advice telling you to use shared examples and run them in the scope of your included controllers.

我个人觉得这太过分了,更喜欢单独执行单元测试,然后使用集成测试来确认我的控制器的行为.

I personally find it over-killing and prefer to perform unit testing in isolation, then use integration testing to confirm the behavior of my controllers.

方法 1:不进行路由或响应测试

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

Create a fake controller and test its methods:

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

方法二:测试响应

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

When your concern contains routing or you need to test for response, rendering etc... you need to run your test with an anonymous controller. This allow you to gain access to all controller-related rspec methods and helpers:

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 之外的另一个类,您将需要对此进行调整.

As you can see, we define the anonymous controller with controller(ApplicationController). If your test concerne another class than ApplicationController, you will need to adapt this.

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

Also for this to work properly you must configure the following in your spec_helper.rb file:

config.infer_base_class_for_anonymous_controllers = true

注意:继续测试您的问题是否包括在内

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

It is also important to test that your concern class is included in your target classes, one line suffice:

describe SomeTargetedController do
  it 'includes MyControllerConcern' do
    expect(SomeTargetedController.ancestors.include? MyControllerConcern).to be(true) 
  end
end

这篇关于如何在 Rails 4 中测试控制器关注点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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