Rspec 在测试 XML 或 CSV 输出时神秘地通过了

Rspec mysteriously passes when testing XML or CSV output

在我的 Rails 5 应用程序中,我有这个:

class InvoicesController < ApplicationController

  def index
    @invoices = current_account.invoices
    respond_to do |format|
      format.csv do
        invoices_file(:csv)
      end
      format.xml do
        invoices_file(:xml)
      end
    end
  end

private

  def invoices_file(type)
    headers['Content-Disposition'] = "inline; filename=\"invoices.#{type.to_s}\""
  end

end

describe InvoicesController, :type => :controller do

  it "renders a csv attachment" do
    get :index, :params => {:format => :csv}
    expect(response.headers["Content-Type"]).to eq("text/csv; charset=utf-8")
    expect(response).to have_http_status(200)
    expect(response).to render_template :index
  end

end

我的问题是我的 Spec 总是 通过 (!),即使我在 index.csv.erb 文件中放了一堆废话。 RSpec.

似乎甚至没有评估/测试视图文件

这怎么可能?我在这里错过了什么?

  1. 格式选项应在参数之外指定,即 get :index, params: {}, format: :csv}.

  2. 关于 RSpec 评估视图,不,在控制器测试中,无论格式如何,它都不会。但是,可以使用 RSpec 测试视图:https://relishapp.com/rspec/rspec-rails/v/2-0/docs/view-specs/view-spec

控制器 tests/specs 是这些奇怪的存根创作,源于孤立的单元测试控制器的想法。这个想法被证明是有缺陷的,最近真的不流行了。

控制器规范实际上不会向通过路由的应用程序发出真正的 HTTP 请求。相反,他们只是伪造它并传递虚假请求。

为了加快测试速度,它们也不会真正渲染视图。这就是为什么它不会像您预期的那样出错。而且响应也不是真正的机架响应对象。

您可以 RSpec 使用 render_views 渲染视图。

describe InvoicesController, :type => :controller do
  render_views
  it "renders a csv attachment" do
    get :index, format: :csv
    expect(response.headers["Content-Type"]).to eq("text/csv; charset=utf-8")
    expect(response).to have_http_status(200)
    expect(response).to render_template :index
  end
end

但更好、更适合未来的选择是使用 request spec

The official recommendation of the Rails team and the RSpec core team is to write request specs instead. Request specs allow you to focus on a single controller action, but unlike controller tests involve the router, the middleware stack, and both rack requests and responses. This adds realism to the test that you are writing, and helps avoid many of the issues that are common in controller specs. http://rspec.info/blog/2016/07/rspec-3-5-has-been-released/

# spec/requests/invoices
require 'rails_helper'
require 'csv'
RSpec.describe "Invoices", type: :request do
  let(:csv) { response.body.parse_csv }
  # Group by the route
  describe "GET /invoices" do
    it "renders a csv attachment" do
      get invoices_path, format: :csv
      expect(response.headers["Content-Type"]).to eq("text/csv; charset=utf-8")
      expect(response).to have_http_status(200)
      expect(csv).to eq ["foo", "bar"] # just an example
    end
  end
end