Testing a Rails API controller
I think you're right to be suspicious of your test setup. Given your code, I imagine you're using #to_json/#as_json in your controllers already, which in effect reduces your test to:

assert_equal record.as_json, record.as_json


which doesn't prove much of anything.

It can also hide bugs. For instance, say your product attributes are name and an optional description, and you expect both to be saved. But your create action accidentally filters away description, so that's never set (and since it's optional, there's no validation error). But you're comparing the created record to itself, you'll never know that the description got lost on the way.

A stricter test would be to say:

attrs = attributes_for(:product)
assert_equal attrs, json_response_body.slice(*attrs.keys)


not pretty, but it's more comprehensive.

(Caveat: If your attributes_for method has some random or sequenced elements, you have to do some boring busywork to make sure it's only called once so you can use it for comparison purposes.)

But it's not totally comprehensive, though. Your response should probably also include added attributes like id, which aren't among the ones you specified in the request.

You could simply add a line like:

assert_equal Product.last.id, json_response_body[:id]


but if you have multiple server-computed attributes to check, this gets annoying too.

You could however use your current helpers for that part. I.e. check some attributes against the ones you posted (so you're sure they made it through), and the computed ones against the Product.last record. That'll help guarantee that the response JSON contains everything you expect it to contain.

All that being said, if your JSON becomes even slightly more complex (e.g. includes associated/nested records), the tests become trickier.

Similarly, your JSON could include values you'll have to check in yet another way. Maybe the JSON response contains something that's neither a saved attribute in the record, or a param you sent. Maybe it contains some random element that changes for each request (don't know why it would, but it's possible), you can't compare it to a known value. Instead you'll have to check it in some other way.

I'm pretty happy with this gem which lets you declare a "pattern" with varying degrees of specificity for the JSON you expect. E.g. you can check that the returned name is the specific string you expect, while id is simply an integer since its exact value isn't important but its type and presence are. Give it a look.