0

I'm realizing I don't understand the rationale for why Rails controller tests / specs are structured the way they are.

When writing controller tests, we're encouraged to more or less treat the controller as a unit and write unit tests accordingly, caring only about the controller's inputs and outputs. For example, we set up a certain state of the database and perhaps stub some Devise methods to simulate a user being logged in, and when we call post :create or whatever, we append a hash of params sent to that controller action.

Then, for the output, we look at the resulting state of the database, we check the response HTTP code and redirect etc., and any assigned variables that will be passed on to the template rendering process.

The controller is just a Ruby class whose public methods are called to execute various RESTful actions. So in controller specs we don't load URLs like /kittens/new; instead we call the controller action directly, like get :new. Routes aren't supposed to be relevant; they're just another part of the system that decides which controller action to call for a given request.

So why do we have to specify the HTTP method (like get, post, put, delete) when calling the controller action? Isn't this an external detail, part of how routing works?

Out of curiosity, I took one of my controller specs and switched all these methods around, ending up with things like delete :show and get :create. Nothing broke. So I'm thoroughly confused: why do we distinguish between these methods if they're not relevant detail to the code that we're testing in controller specs?

Topher Hunt
  • 4,404
  • 2
  • 27
  • 51

2 Answers2

1

I'm not exactly sure if this is why it's still around, but pre-REST, a lot of apps used the same endpoint for new and create. (Like, you might have a controller with a new_review action, and if you hit it with a GET, it'd show the review form, and if you hit it with a POST, it'd save the review.) In these controller actions, you'd see if request.post?.

Nowadays, you see that a lot less often (thankfully), but it's still supported. So by putting the HTTP method in your test, you can make sure that the request object behaves the way you expect it to in your controller action.

Justin Weiss
  • 1,128
  • 7
  • 10
  • Ahh got it. Yeah I remember seeing a few of those and thinking "Wow, that's a nifty way to reduce the number of controller actions" but I never really thought about the implications for testing. Thanks! – Topher Hunt Feb 05 '15 at 13:31
0

As summed up here (REST API - why use PUT DELETE POST GET?)

REST is a methodology for meaningful access of data. When you see a request in REST, it should immediately be apparant what is happening with the data.

Therefore, you preface the HTTP verb intended to result in the calling of your action.

This is important since for scenarios not using any of 7 default controller actions. For instance, disable_accounts, are we suggesting GET /disabled_accounts or PATCH /disabled_accounts?

Community
  • 1
  • 1
user1322092
  • 4,020
  • 7
  • 35
  • 52
  • This summarizes why the REST verbs matter in general, but doesn't seem to address my question, which is: why do we need to use these REST verbs in the controller specs, when we're already directly connecting with the desired action by name? My understanding of the REST verbs is that they're mainly used to decide which controller action to call, so in testing the controller they seem like an external detail. – Topher Hunt Feb 03 '15 at 15:28