4
\$\begingroup\$

I'm writing a (nearly-)single-page app using Ruby on Rails 3.1 and Backbone.js. Thus, most of my controllers return rootless JSON, courtesy this setting as per the Backbone.js docs:

ActiveRecord::Base.include_root_in_json = false

So the returned JSON for an account, say, looks like this:

{
  "created_at":"2011-12-27T22:23:17Z",
  "id":1,"name":"My Happy Account",
  "updated_at":"2011-12-27T22:23:17Z"
}

I'm testing that this works in the following way:

it 'returns the account associated with the current user' do
  get :current, :format => :json

  assert_response(:success)
  account = JSON.parse(response.body)
  account['name'].should == @account_one.name
  account['id'].should == @account_one.id
end

The spec passes but I can't help feel that it's a bit icky and not very idiomatic perhaps. Could someone please suggest a nicer way of doing this?

\$\endgroup\$
  • \$\begingroup\$ What in particular feels icky or non-idiomatic about this? My app is also a single-page Backbone/Rails 3.1 app, and my tests are similar to this. My tests are a bit more broken down -- generally just one assertion per it/specify block -- but otherwise it amounts to the same thing: parse the response, make assertions on the key-value pairs. \$\endgroup\$ – Jeff Dec 30 '11 at 6:04
  • \$\begingroup\$ I guess you should also ask yourself what an idiomatic test would look like if you were testing a multi-page, non-Backbone app. You might check assigned values or that a specific is rendered. In this case there is no template to render, so that's out, but checking assigns seems analogous to what you're testing. There's just less syntactic sugar in your case. \$\endgroup\$ – Jeff Dec 30 '11 at 6:12
2
\$\begingroup\$

I think your method of testing is fine.

My app is also a single-page Backbone/Rails 3.1 app, and my tests are similar to yours. My tests are a bit more broken down -- I generally aim for one assertion per it / specify block -- but the substance of the tests amounts to the same thing: make a request, parse the response, and make assertions based on what the response contains versus what I expect that it should contain.

The crucial question to ask yourself here is what idiomatic controller tests might look like in a more traditional, multi-page, non-Backbone app. You're generally checking a few things in those tests:

  1. A particular value is assigned
  2. A particular template is rendered, or that you've redirected to a particular URL
  3. The response code matches your expectation

For item 1, I think that amount to parsing the response and looking for a particular value. RSpec-Rails gives you the nice sugar of the assigns statement, which makes things look a bit cleaner, but in my mind the intent is the same as what you're doing. You could pretty easily write your own sugar to wrap the parsed JSON response body, if you wanted, so you could write something like json_response(:name).should == @account_one.name, where json_response is the name of the helper method you would write. (The implementation basically amounts to parsing the response body and looking up the value for the key passed as a method argument.) Do that and the tests look a lot more like those for a non-Backbone app.

Item 2 doesn't apply to a single-page Backbone app, since you're always on the same page. So that's out.

Item 3 is the same as in a non-Backbone app. You have assert_response(:success), which is fine. I like to do something like response.status.should eq(200), or whatever is appropriate for the status code I expect. I find that I check status codes more often in my Backbone app's tests than in a more "traditional" multi-page app, just because I like to return appropriate HTTP status codes when possible as error response in Ajax apps, whereas in a multi-page app I might be returning a 200 status with some error message on the page like "Email address is mandatory." YMMV, in this regard.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.