17

I can't find anything explaining how to test routes in Rails 3. Even in the Rspec book, it doesn't explain well.

Thanks

donald
  • 23,587
  • 42
  • 142
  • 223
  • [Example Rspec Routes](https://cbabhusal.wordpress.com/2015/12/15/rails-rspec-examples-of-routing-specs/#more-1623) – Shiva Dec 15 '15 at 03:33

2 Answers2

32

There is a brief example on the rspec-rails Github site. You can also use the scaffold generator to produce some canned examples. For instance,

rails g scaffold Article

should produce something like this:

require "spec_helper"

describe ArticlesController do
  describe "routing" do

    it "routes to #index" do
      get("/articles").should route_to("articles#index")
    end

    it "routes to #new" do
      get("/articles/new").should route_to("articles#new")
    end

    it "routes to #show" do
      get("/articles/1").should route_to("articles#show", :id => "1")
    end

    it "routes to #edit" do
      get("/articles/1/edit").should route_to("articles#edit", :id => "1")
    end

    it "routes to #create" do
      post("/articles").should route_to("articles#create")
    end

    it "routes to #update" do
      put("/articles/1").should route_to("articles#update", :id => "1")
    end

    it "routes to #destroy" do
      delete("/articles/1").should route_to("articles#destroy", :id => "1")
    end

  end
end
zetetic
  • 47,184
  • 10
  • 111
  • 119
  • I have a problem with these type of testing, this is my quesiton http://stackoverflow.com/questions/14330293/rspec-for-routes-and-testing-routes-rb-specifically#comment19916220_14330293, pretty much it doesn't verify if the route exist in the routes.rb, it just goes with the syntanx check. Any ideas? – Matilda Jan 15 '13 at 03:32
-8

Zetetic's answer explains how to test routes. This answer explains why you shouldn't do that.

In general, your tests should test the behavior exposed to the user (or client object), not the implementation by which that behavior is provided. Routes are user-facing: when the user types in http://www.mysite.com/profile, he doesn't care that it goes to ProfilesController; rather, he cares that he sees his profile.

So don't test that you're going to ProfilesController. Rather, set up a Cucumber scenario to test that when the user goes to /profile, he sees his name and profile info. That's all you need.

Again: don't test your routes. Test your behavior.

Marnen Laibow-Koser
  • 5,959
  • 1
  • 28
  • 33
  • 2
    It would be nice if whoever is downvoting this would leave a comment explaining why they're doing so... – Marnen Laibow-Koser Dec 05 '11 at 02:40
  • 1
    Generally not. Unit testing is useful at the model level -- where internal business logic (independent of the UI) is involved. At the controller level, however, only the UI is relevant, so testing controller implementation really doesn't tell you anything useful. If someone told me I had to choose between having Cucumber stories and having RSpec model specs, I'd take the Cucumber stories every time. (Fortunately, I don't have to choose. :) ) – Marnen Laibow-Koser Jan 09 '12 at 16:11
  • 2
    I disagree with your assumptions here. There might be reasons why you want to test routes, you could have routes with constraints, you could have routes that dynamically get created, routes that return rack apps, etc. – Agustin Apr 06 '12 at 03:08
  • 1
    @Agustin True. And I think none of those change my claim in the least. If I create a route dynamically (which isn't great practice anyway), I don't want to test that it points to a particular controller; rather, I want to test that it gets to a particular piece of the UI. Routes are for the user. UI is for the user. Controllers are implementation. – Marnen Laibow-Koser Apr 06 '12 at 04:57
  • 1
    Even if your cucumber tests pass, it doesn't mean that you won't have routing errors. And testing routes increases test coverage. – Vanuan May 13 '12 at 10:05
  • 1
    @Vanuan If your Cucumber tests are comprehensive enough, then they'll generally exercise all your routes. So testing routes separately won't increase coverage (at C0, at least). Anyway, there's no point to increasing coverage in a way that doesn't actually test anything useful. Coverage numbers don't tell the whole story. – Marnen Laibow-Koser May 13 '12 at 15:00
  • 1
    @Vanuan I can't think of a scenario where my Cucumber tests could pass if I had routing errors in the part of the app they cover. Can you? – Marnen Laibow-Koser May 13 '12 at 15:01
  • Consider javascript_include_tag. Cucumber doesn't load a page like a browser does. – Vanuan May 13 '12 at 15:06
  • 1
    @Vanuan Actually, Cucumber does load a page like a browser does -- the differences are more in DOM interpretation (and you can get rid of them by having Cucumber drive a browser engine). I don't see how `javascript_include_tag` has anything to do with routing in Cucumber. Can you be more specific about the scenario you're thinking of? – Marnen Laibow-Koser May 15 '12 at 01:18
  • I have a route to the controller which generates javascript. Javascript is included via "javascript_include_tag" into a page that cucumber test covers. That test passes even if route to the javascript generator is broken. – Vanuan May 15 '12 at 11:09
  • The point I'm trying to prove is that you can't be sure that your tests are comprehensive enough. There'll always be edge cases where integration tests suck. See the article http://blog.thecodewhisperer.com/2010/10/16/integrated-tests-are-a-scam And I wan't to be told "Your route /profile is broken" instead of "Can't load the profile page" or "A profile page doesn't have a user name". It doesn't mean that integration tests are bad. It just means that there's nothing wrong in testing routes. – Vanuan May 15 '12 at 11:27
  • @Vanuan Your JS scenario should fail if the route is broken, because the JS functionality won't be there, and your scenario should be testing that. So your example doesn't work. (Anyway, dynamically generated JS is usually a design problem.) – Marnen Laibow-Koser May 15 '12 at 13:55
  • 1
    @Vanuan 'And I wan't to be told "Your route /profile is broken"' -- Cucumber already does exactly that: it will pass through the Rails 'no route found' error. 'It just means that there's nothing wrong in testing routes.' -- No. There's a lot wrong with testing routes. From your examples, I think you may need to learn more integration testing skills. – Marnen Laibow-Koser May 15 '12 at 13:57
  • 1
    My guess is they downvoted because your response doesn't answer the question. – thekingoftruth Aug 30 '12 at 22:03
  • 1
    @Vanuan BTW, I just read that blog post you linked to (and the following ones in the series). I think it's ridiculous—particularly since the author never explains how to take the place of the integration tests he doesn't like. He claims not to be able to provide examples, which is kind of an interesting point in itself. – Marnen Laibow-Koser Feb 13 '13 at 20:04
  • 1
    Am I missing the obvious here? *Unit* tests test one piece/layer of a system in *isolation*. Route tests do exactly that, they test your route configuration, nothing else. Anything that tests more than that, like route + controller, is an integration test. You want those as well to make sure the pieces fit together, but they can never be exhaustive. That's why you should have at least two layers of tests, the outer layer (complete app integration) and the inner layer (unit). You can test smaller integrations like just a couple of objects if that makes sense for your app. – Arne Brasseur Jun 11 '13 at 15:25
  • @ArneBrasseur That's true, of course. The point is that routes, by themselves, don't do anything for which it's meaningful to unit test as far as I can tell (unlike models, which encapsulate a lot of logic and need separate testing). Since unit tests for routes are largely meaningless, and since integration tests, if written properly, will test the routes in a much more meaningful way, I see no reason to unit-test my routes. Do you disagree? If so, why? (Note: I generally believe that integration tests [which, for me, means Cucumber] are much more generally useful than unit tests.) – Marnen Laibow-Koser Jun 14 '13 at 18:22
  • 2
    The app I'm working on (client work) has a routes.rb file that has now grown to 1042 lines. Not great but that's reality. Lots of nested routes, some complex constraints, some routes that partly shadow resourceful routes declared later. It's a mess for sure, but sometimes I need to get in there and change or add things, in that case it's great to have a test that verifies that the route works as I expected. – Arne Brasseur Jun 15 '13 at 17:41
  • 1
    @ArneBrasseur Yes, but I think you're missing an important point here. I think that routes work "as expected" if they point to a certain bit of *functionality*, not a certain *controller*. That's why I don't think testing routes in isolation is meaningful. – Marnen Laibow-Koser Jun 25 '13 at 19:22
  • 1
    Then we disagree, because what routes do is mapping a request to a controller action. A route unit test verifies that level, and that's it, or it is no longer a unit test. That you seem to have more faith in integration tests is unrelated. – Arne Brasseur Jun 26 '13 at 14:24
  • 1
    @ArneBrasseur I agree that routes map a request to a controller action, but I don't think we care about the name of the action, as long as the functionality is correct. From a testing point of view, I really don't care if `/books/1` goes to `BooksController#show` or `KoalasController#feed` as long as it does what I expect it to when I go there—which my integration tests will verify. That's why I find unit-testing routes to be completely pointless in nearly all cases. – Marnen Laibow-Koser Jun 26 '13 at 14:46
  • You have a very good point. Personally, I prefer to have both unit and high-level integration (or also called, feature) tests. – Evgenii Nov 05 '13 at 22:20
  • 1
    @Evgeny I do too. But unit tests aren't useful for everything, and I try not to write them where they aren't useful. – Marnen Laibow-Koser Nov 05 '13 at 22:53