Testing Controllers with respond_to?

Hello,

I’m having a hard time testing my controllers that use respond_to.
I’m trying to test that I can correctly handle each MIME type on
request.

For instance, I have this:

respond_to do |format|
  format.html
  format.json
end

And I’ve tried things like this:

get ‘show’, :id => databases(:one).id, :format => ‘json’
response.should render_template(‘show’)

but I keep getting a nil template.

I know this works in the code, when I try a URI like
http://localhost:3000/foo.json

Any tips for setting the format or MIME Type correctly so I can
activate other respond_to blocks?

Thanks very much,
Seth

Hm, of course, now that I have sent the previous email, I found the
bug in my code and have fixed it. So I know I am using RSpec
correctly with controllers and a respond_to block. Using the :format
=> ‘json’ attribute in my get call was all I needed.

However, not matter what the format I choose, the template rendered is
always “databases/show” (this is essentially correct behavior).
However, it’s hard to determine which show was rendered:
show.json.erb or show.html.erb

I can check the content-type header, but that’s not exactly what I’d
like to test.

Is there a better way to write a spec to ensure that the correct
template is rendered when I use certain formats?

Seth

On Tue, Mar 25, 2008 at 2:06 AM, Seth L. [email protected] wrote:

Hm, of course, now that I have sent the previous email, I found the
bug in my code and have fixed it. So I know I am using RSpec
correctly with controllers and a respond_to block. Using the :format
=> ‘json’ attribute in my get call was all I needed.

However, not matter what the format I choose, the template rendered is
always “databases/show” (this is essentially correct behavior).
However, it’s hard to determine which show was rendered:
show.json.erb or show.html.erb

There is a guideline in TDD that you should test your code and not
other people’s code. The behaviour you’re interested in testing is
that of ActionController::Base, not of your code.

I can check the content-type header, but that’s not exactly what I’d
like to test.

Is there a better way to write a spec to ensure that the correct
template is rendered when I use certain formats?

The transformation from loosely-bound name (‘databases/show’) to
explicit template name with extensions happens deep in
ActionController::Base. Between that fact and the aforementioned
guideline, there is no direct support for what you are looking for in
rspec_on_rails.

You can do this to get closer to what you are looking for:

  controller.expect_render(hash_including(:xml => anything))

or

  controller.expect_render(hash_including(:json => anything))

But I, personally, would not. Since this is not supported directly by
rspec_on_rails, should the Rails implementation of render change you’d
be on your own to keep up with those changes.

HTH,
David

There is a guideline in TDD that you should test your code and not
other people’s code. The behaviour you’re interested in testing is
that of ActionController::Base, not of your code.

I, of course, do not want to test Rails. I do, however, want to
ensure that I have a block to handle the correct MIME type and I have
a template for that MIME type. I suppose checking for the template
“foo/show” is good enough in this case. If there was an error, I’d
get a nil there.

I guess where this strategy falls down is if I forgot to put a
responds_to in my controller. Then, no matter the format, I’ll still
render ‘foo/show’ (assuming I do indeed have that template)

Thanks for your help,
Seth

On Tue, Mar 25, 2008 at 11:38 AM, Seth L. [email protected] wrote:

There is a guideline in TDD that you should test your code and not
other people’s code. The behaviour you’re interested in testing is
that of ActionController::Base, not of your code.

I, of course, do not want to test Rails. I do, however, want to
ensure that I have a block to handle the correct MIME type and I have
a template for that MIME type. I suppose checking for the template
“foo/show” is good enough in this case. If there was an error, I’d
get a nil there.

If you’re really concerned about it, you could also mock respond_to:

format = mock(“format”)
format.should_receive(:json).and_return(“this text”)
controller.should_receive(:respond_to).and_yield(format)
get ‘path/to/file’, :format => ‘json’

That seems a bit implementation heavy, but it might give you the
feeling of confidence you’re looking for.

HTH,
David

Hi Seth,

To get around this, are you able to test the response.headers
collection? This tests the code that you wrote, rather than the
template logic performed by rails.

response.headers[‘Content-Type’].should == “text/html”

Untested, of course… but it may work :slight_smile:


Matt Berther

To do this, I’ve typically just add the HTTP_ACCEPT header. I can’t
remember where I picked this up, but it’s does specify a format in
your respond_to block:

Here’s the do_request (and a sample spec) for one of my specs where
I’m checking for a generated csv file:
def do_request
@request.env[“HTTP_ACCEPT”] = “text/csv”
get :show, :id => “1”
end

it “should return a csv download” do
@controller.should_receive(:send_file).with(@file, {:filename =>
“report-#{@report.id
}.csv”, :type => ‘text/csv’, :disposition => ‘attachment’})
do_get
end

Now my assumption is that your mime-type would need to be registered
in rails for this to work (if you have need of one outside of the
norm), which arguably has the added benefit of ensuring you added it
into your environment initializers…

Tim G.