使用Rails 5和Rspec进行动态渲染

时间:2017-09-26 08:15:43

标签: ruby-on-rails rspec rspec-rails

我正在尝试测试我的控制器通过请求规范呈现正确的状态代码。此应用程序使用一些带有动态类名的元编程来呈现视图。如何在下面存根渲染调用以返回我的规范所需的正确状态代码?

Rspec Spec Snippet

context 'renders 200' do
  let(:provider_slug) { create(:provider, :active).slug }
  let(:template) { "providers/v1/#{provider_slug}/new" }
  let(:layout) { "providers/v1/#{provider_slug}" }

  let(:provider_double) do
    instance_double(
      ProviderRouter,
      valid?: true,
      form_model: ProviderFormModel
    )
  end

  before do
    allow(ProviderRouter).
      to receive(:new).with(version: 'V1', provider_slug: provider_slug).
      and_return(provider_double)

    allow(described_class).to receive(:render_new_form).and_return(true)

    get route
  end

  it 'true' do
    expect(response.status).to be(200)
  end
end

控制器代码段

class V1::ProvidersController < ApplicationViewController
  before_action :init_provider, :init_form_types, :validate_provider

  def new
    @provider_form_model = provider_router.form_model.new
    render_new_form
  end

  private

  attr_reader :provider_slug, :provider_path, :provider_router, :provider_model

  def render_new_form
    render template: "providers/v1/#{provider_slug}/new", layout: "providers/v1/#{provider_slug}"
  end

针对以下答案进行了更新

context 'renders 200' do
  let(:provider_slug) { create(:provider, :active).slug }

  let(:provider_double) do
    instance_double(
      ProviderRouter,
      valid?: true,
      form_model: ProviderFormModel
    )
  end

  before do
    allow(ProviderRouter).
      to receive(:new).with(version: 'V1', provider_slug: provider_slug).
      and_return(provider_double)

    allow(controller).to receive(:provider_slug).and_return(provider_slug)

    allow(controller).to receive(:render).and_call_original

    allow(controller).to receive(:render).
      with(template: "providers/v1/#{provider_slug}/new", layout: "providers/v1/#{provider_slug}") do
      controller.render plain: '200 [OK]'
    end

    get "/v1/providers/#{provider_slug}"
  end

  it 'true' do
    expect(response.status).to be(200)
  end
end

1 个答案:

答案 0 :(得分:0)

正式的答案是你不应该将它存根,因为你要对被测对象的行为进行存根。

您应该提供provider_slug用于测试。

从技术上讲,可以这样做:

allow(controller) # controller is the instance of the ProvidersController used under the hood
   .to_receive(:render_new_form)
   .and_return("some bogus value")

但是这会导致rails尝试渲染默认模板,因为还没有渲染。因此,实际调用render方法是有帮助的,该方法可以通过以下方式实现:

# we call the render method in our stub and thus have to be able to call the original
allow(controller)
  .to receive(:render)
  .and_call_original

allow(controller)
   .to_receive(:render) # not render_new_form
   .with(template: anything, layout: anything) do
  controller.render plain: '200 [OK]'
end