문제

무엇을 처리하는 가장 좋은 방법은 시험의 우려 때에 사용되는 레일 4 컨트롤러?가 사소한 관심사 Citations.

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

예상 동작은 아래에서 테스트하는 모든 컨트롤러를 포함하는 이 관심을 얻을 것이라이 citations 엔드포인트가 있습니다.

class ConversationController < ActionController::Base
    include Citations
end

간단합니다.

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

그러나 무엇이 올바른 방법으로 이를 테스트에서 우려가?

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

이것은 인위적인 예이다.내 응용 프로그램에,나는 다른 오류가 있습니다.

RuntimeError:
  @routes is nil: make sure you set it in your test's setup method.
도움이 되었습니까?

해결책

공유 예제를 사용하도록 알려주고 포함 된 컨트롤러의 범위에서 실행하라는 많은 조언을 찾을 수 있습니다.

나는 개인적으로 그것을 과도하게 살해하고 단위 테스트를 수행하는 것을 선호하고 통합 테스트를 사용하여 컨트롤러의 행동을 확인합니다.

방법 1 : 라우팅 또는 응답 테스트없이

가짜 컨트롤러를 만들고 메소드를 테스트하십시오.

describe MyControllerConcern do

  before do
    class FakesController < ApplicationController
      include MyControllerConcern
    end
  end
  after { Object.send :remove_const, :FakesController }
  let(:object) { FakesController.new }

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

end
.

방법 2 : 응답 테스트

사용자의 관심사가 포함되거나 응답을 테스트해야 할 필요가 있습니다. 렌더링 등 ... 익명 컨트롤러로 테스트를 실행해야합니다. 이렇게하면 모든 컨트롤러 관련 RSPEC 메서드 및 도우미에 액세스 할 수 있습니다.

describe MyControllerConcern, type: :controller do

  controller(ApplicationController) do
    include MyControllerConcern

    def fake_action; redirect_to '/an_url'; end
  end
  before { routes.draw {
    get 'fake_action' => 'anonymous#fake_action'
  } }


  describe 'my_method_to_test' do
    before { get :fake_action }
    it { expect(response).to redirect_to('/an_url') }
  end
end
.

익명의 컨트롤러를 controller(ApplicationController)에서 래핑해야 함을 알 수 있습니다. 클래스가 ApplicationController보다 다른 클래스에서 상속되면이를 적용해야합니다.

또한 올바르게 작동하려면 spec_helper.rb 파일에서 선언해야합니다.

config.infer_base_class_for_anonymous_controllers = true
.

참고 : 관심사가 포함 된 테스트를 계속 포함합니다

사용자의 우려 수업이 목표 수업에 포함되어 있음을 테스트하는 것도 중요합니다.

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

다른 팁

가장 투표 한 답변에서 방법 2를 간소화합니다.

RSPEC http : //www.relishapp에서 지원되는 anonymous controller를 선호합니다.COM / RSPEC / RSPEC-RAILS / DOCS / 컨트롤러 -PICS / 익명 컨트롤러

당신은 할 것입니다 :

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를 설명하고 유형을 설정해야합니다.

내 대답게 보일 수 있습보다 조금 더 복잡한 이해@Benj 및@Calin 지만,그것은 장점이 있습니다.

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 도 다른 어떤 기본 컨트롤러에서 정의된 응용 프로그램입니다.이 방법은 당신할 수 있을 테스트하는 관심사에서는 분리에서 당신의 컨트롤러입니다.기대할 경우에는 몇 가지 방법에 정의해야 하는 기본 컨트롤러,단 stub 니다.

또한,그것은 좋은 생각을 피하기 위해 다시 입력한 우려에 모듈 이름을 방지하는 데 도움이 복사하여 붙여넣 오류가 있습니다.불행하게도, described_class 액세스할 수 없 블록에 전달된 controller(ActionController::Base), 다,그래서 사용 #tap 을 만들 수 있는 방법이 다른 바인딩하는 상점 described_class 에서 지역 변수입니다.이 경우 특히 중요 작업으로 버전을 지정한다.그러한 경우에 그것은 아주 일반적인 복의 큰 볼륨 컨트롤러를 만들 때 새로운 버전,그리고 그것은 정말 쉽게 만들은 미묘한 복사하여 붙여넣기 실수하다.

저는 내 컨트롤러 문제를 테스트하는 간단한 방법을 사용하고 있으며, 이것이 올바른 방법인지 확실하지는 않지만 위의 것들이 훨씬 더 간단 해져서 포함 된 컨트롤러의 범위를 사용하는 것이 훨씬 간단 해지는 것처럼 확실합니다.이 방법에 문제가 있는지 알려주십시오. 샘플 컨트롤러 :

class MyController < BaseController
  include MyConcern

  def index
    ...

    type = column_type(column_name)
    ...
  end
.

end

내 컨트롤러 문제 :

module MyConcern
  ...
  def column_type(name)
    return :phone if (column =~ /phone/).present?
    return :id if column == 'id' || (column =~ /_id/).present?
   :default
  end
  ...

end
.

우려를위한 사양 테스트 :

require 'spec_helper'

describe SearchFilter do
  let(:ac)    { MyController.new }
  context '#column_type' do
    it 'should return :phone for phone type column' do
      expect(ac.column_type('phone')).to eq(:phone)
    end

    it 'should return :id for id column' do
      expect(ac.column_type('company_id')).to eq(:id)
    end

    it 'should return :id for id column' do
      expect(ac.column_type('id')).to eq(:id)
    end

    it 'should return :default for other types of columns' do
      expect(ac.column_type('company_name')).to eq(:default)
    end
  end
end
.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top