【问题标题】:Dynamic rendering with Rails 5 and Rspec使用 Rails 5 和 Rspec 进行动态渲染
【发布时间】:2017-10-07 18:56:50
【问题描述】:

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

Rspec 规范片段

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

【问题讨论】:

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


    【解决方案1】:

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

    您应该提供一个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
    

    【讨论】:

    • 谢谢@ulferts,我同意slug,但它们可以是完全动态的,并且在生成的版本中不会存在。总的来说,对于功能测试,我喜欢它的发展方向,即使它只是一个学习示例。我更新了问题以反映您的第二个选项,但我仍然收到“ActionView::MissingTemplate: Missing template”错误。
    • @ChrisHough 请您尝试实际使用template: anything, layout: anything 作为with 的值(而不是template: "/v1/providers/#{provider_slug}.new", layout: "providers/v1/#{provider_slug}")。使用该通配符将对更改更具弹性。 provider_slug 是您的情况下 let 块的结果。
    • 我接受了您的编辑,但它仍然不起作用。想法?
    • 我为您的问题发送了一个编辑请求,该请求修复了渲染方法的反向路径期望。在本地设置类似的应用程序并遇到相同的问题后,我可以重现该问题。因此,我非常肯定,修正期望应该修正错误。
    • 不幸的是,我仍然收到Missing template providers/v1/rosenbaum/new with,例如@ulferts
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 2018-06-25
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多