简体   繁体   中英

Rspec mysteriously passes when testing XML or CSV output

In my Rails 5 app I have this:

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

My problem is that my Spec always passes (!), even when I put a bunch of crap into my index.csv.erb file. It seems that the view file isn't even evaluated / tested by RSpec.

How is this possible? What am I missing here?

  1. The format option should be specified outside of the params, ie get :index, params: {}, format: :csv} .

  2. Regarding RSpec evaluating views, no, in controller tests, it doesn't, regardless of the format. However, it's possible to test views with RSpec: https://relishapp.com/rspec/rspec-rails/v/2-0/docs/view-specs/view-spec

Controller tests/specs are these weird stubbed creations born out of the idea of unit testing controllers in isolation. That idea turned out to be pretty flawed and has really fallen out of vogue lately.

Controller specs don't actually make a real HTTP request to your application that passes through the routes. Rather they just kind of fake it and pass a fake request through.

To make the tests faster they also don't really render the views either. Thats why it does not error out as you have expected. And the response is not really a real rack response object either.

You can make RSpec render the views with 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

But a better and more future proof option is using a 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM