Adding Routes for Tests »

Created at: 23.06.2009 01:25, source: Rail Spikes - Home, tagged: routes testing tips

I like to be extremely judicious with use of routes. Fewer routes means less memory consumption and fewer confusing magical methods.

I always delete the default route map.connect ':controller/:action/:id' (you should too, otherwise all your pretty RESTful routing is easily circumvented). Since Rails now has the ability to remove unneeded RESTful routes, I’ve been removing those, too.

However, this judiciousness recently painted me into a corner. I have a controller action that I would like to test and it’s wired up like this:

map.logout '/logout', :controller => 'user_sessions', :action => 'destroy', :method => 'delete'

I don’t have this mapped any other way, because why should I?

1
2
3
4
5
6
7
8
def test_logout_should_redirect_to_root_path
  UserSession.create(User.first)

  delete :destroy

  assert_match /logged out/, flash[:notice]
  assert_redirected_to root_path
end

Unfortunately, the test fails with ActionController::RoutingError: No route matches {:action=>"destroy", :controller=>"user_sessions"}! Huh?

The problem is that the delete (and get, post, etc.) method can’t find the route that I created.

Initially, I worked around this using with_routing to define a whole new set of routes just for that test.

1
2
3
4
5
6
7
8
9
10
11
with_routing do |set|
  set.draw do |map|
    map.resource :user_sessions, :only => [:destroy]
    map.root :controller => 'foobars', :action => 'index'
  end

  delete :destroy

  assert_match /logged out/, flash[:notice]
  assert_redirected_to root_path
end

But that was annoying. And after I had more than one route exhibiting this problem, it got really annoying.

Fortunately, I found Sam Ruby’s post Keeping Up With Rails about the challenge of Rails’ minor, quasi-documented API changes. Sam’s post has a bit about how you can add new routes without clearing the existing routes in Rails 2.3.2, which I knew was possible. Following Sam’s link to the commit (there’s no docs for this) showed how to do it.

Now, I’ve added this to test_helper.rb:

1
2
3
4
class ActionController::TestCase
  # add a catch-all route for the tests only.
 ActionController::Routing::Routes.draw { |map| map.connect ':controller/:action/:id' }
end

The downside to this is that real problems with broken routes may get swept under the rug. You could be more restrictive with the routes you are adding just for tests to overcome that problem.

Update: Thanks to Adam Cigánek in the comments for pointing out my error in why the route didn’t get picked up in the tests. I had the condition hash wrong!

Instead of:

map.logout '/logout', :controller => 'user_sessions', :action => 'destroy', :method => 'delete'

It should be:

map.logout '/logout', :controller => 'user_sessions', :action => 'destroy', :conditions => {:method => :delete}

The first way I had worked correctly when testing manually, but only because without :method, the route responds to all HTTP methods (still no clue why my test didn’t pick it up, though).

Interestingly enough, there’s another gotcha here. Notice that I specified :method => 'delete'. Even when put into the :conditions hash, that doesn’t work. You MUST pass a symbol (:delete) for the HTTP method.

This fixed my problem, but if I ever do need to add routes for tests, now I know how…


more »

20 articles on Cucumber and a free beverage recipe! »

Created at: 10.04.2009 06:22, source: Robby on Rails, tagged: Ruby on Rails ruby programming ruby rspec cucumber testing tdd bdd links recipe water

Cucumber has been getting quite a bit of attention in the community and with the new RSpec Book on nearing publication, I predict that by this time next year, it’ll become a household word like boanthropy.

What is Cucumber?

The Cucumber project describes itself as a suite that, “lets software development teams describe how software should behave in plain text. The text is written in a business-readable domain-specific language and serves as documentation, automated tests and development-aid – all rolled into one format.

One of the great things about Cucumber is that it can be used to test applications in any language. I haven’t been able to track down a lot of articles of how people are using it with other languages, so please comment if you’re aware of some.

In any event, I’ve been collecting and reading resources from a variety of Cucumber aficionados and thought I’d share some links with you. To round it out, I asked on twitter for some others so that I could hit twenty. :-)

  1. What’s in a Story?, Dan North
  2. Telling a good story – Rspec stories from the trenches, Joseph Wilk
  3. Beginning with Cucumber, Ryan Bates (Railscasts)
  4. Using RSpec, Cucumber and User stories to build our internal systems, Rahoul Baruah
  5. Cucumber: The Latest in Ruby Testing, Ruby Inside
  6. Using Cucumber for Acceptance Testing, Noel Rappin
  7. Behavior Driven Development with Cucumber, Brandon Keepers (presentation/slides)
  8. Testing capistrano recipes with cucumber, Jeff Dean
  9. Using Cucumber to Integrate Distributed Systems and Test Messaging, Ben Mabey
  10. Tutorial: How to install/setup Cucumber, Alan Mitchell
  11. Testing outbound emails with Cucumber, Dr. Nic Willians
  12. Proper Cucumber Sintatra Driving, Chris Strom
  13. On getting started using Cucumber for .NET
  14. DRY up your Cucumber Steps, Matt Wynne
  15. Cucumber, Celerity, & FireWatir, Aidy Lewis (presentation/video)
  16. Cucumber step definition tip: Stubbing time, Bryan Helmkamp
  17. Story Driven Development Recipes with Cucumber, Sebastien Auvray
  18. Testing Facebook with Cucumber, Brandon Keepers
  19. Testing with the help of machinist, forgery, cucumber, webrat and rspec, Etienne van Tonder
  20. Integration testing SSL with Cucumber
  21. Continuous Integration Blueprints: How to Build an Army of Killer Robots With Hudson and Cucumber

So.. there you have it. Please post comments with links to any useful articles not mentioned and I’ll try to keep the list updated.

Also, be sure to check out the list of tutorials and related blog posts on the cucumber wiki (github).

FREE RECIPE: Cucumber Water

And now…for the reason you are all here! If you like cucumbers (eating them)... I would highly recommend heading to your local farmers market and purchasing some cucumbers. Aside from being healthy to eat… they can help make a tasty beverage.

Then do the following…

  • Chop several slices of a cucumber
  • Fill a pitcher with cold water and ice
  • Toss in slices of cucumber
  • Stir and leave in fridge for a while
  • Take out of fridge, pour into cup…
  • Drink… hack… and enjoy

Be sure to check out, How to Make Cucumber Water on wikihow for details.

Happy Hacking!

Related Posts (by me)


more »

Testing Attachment Fu in Rails Test Unit »

Created at: 10.04.2009 05:19, source: Hackido, tagged: rails testing

Whether you're using standard Test Unit or Shoulda, you should be testing models. But if a User model has to have a Photo, how do you set up a unit test to make sure it passes? I've read blog posts and forums threads on the issue but never found anything comprehensive enough for a entry-level rails tester to understand. So, with that in mind, read on for a quick tutorial.


I'm using Shoulda so my tests are geared for that syntax. If you're using Test Unit, feel free to modify accordingly. The meat of the answer is still the same.

First of all, let's assume you're in the test/unit/user.rb file doing your unit test. Your file starts off looking like this:

require File.join(File.dirname(__FILE__),"..","test_helper")

class UserTest < ActiveSupport::TestCase
end


You'll want to add your context block, setup block, and an assertion too.


context "A new user with a valid photo" do
setup do
@user = User.create(:email => "test@example.com", :login => "test", :password => "password123", :password_confirmation => "password123")
end

should "be a valid user" do
assert(@user.valid?)
end
end


Running the above test won't work if you're requiring a photo because you haven't actually set one up. To do that you'll have to use create the photo in the test like this:

@photo = Photo.create(:uploaded_data => fixture_file_upload("/files/mugshot.png",'image/png')


The tricky part is that the fixture_file_upload is a part of ActionController::TestProcess. So you'll need to include it for it to work. The final user.rb will therefore look like this:

require File.join(File.dirname(__FILE__),"..","test_helper")

class UserTest < ActiveSupport::TestCase
include ActionController::TestProcess
context "A new user with a valid photo" do
setup do
@photo = Photo.create(:uploaded_data => fixture_file_upload("/files/mugshot.png",'image/png'))
@user = User.create(:email => "test@example.com", :login => "test", :password => "password123", :password_confirmation => "password123", :photo => [@photo])
end

should "be a valid user" do
assert(@user.valid?)
end
end
end


Now when you run your test, it should pass:
ruby test/unit/user.rb

Started
.
Finished in 0.196 seconds.

1 tests, 1 assertions, 0 failures, 0 errors


A few things to look out for:

  • - The above assumes a User has many Photos which is why it's photos => [@photo] and not photo => @photo.

  • - You'll need to create a file called mugshot.png and put it in the test/fixtures/files directory (which you probably need to create)

  • - I'm using Shoulda, if you use straight test::unit or rspec, you'll need to change things appropriately.

  • - My example also assumes the only things required in your user model is the email, login, password, and photo. Adjust accordingly.


Hopefully the above works for you. Now that you're validating attachments correctly there's no reason not to do more testing!


more »

db fixtures replacement solution step by step »

Created at: 07.09.2008 19:06, source: Rails on the Run - Home, tagged: datamapper factory_girl fixtures merb rspec rspec spec testing

Like most people who started with Rails a while back, I first loved Rails fixtures and ended up hating them (slow, a pain to maintain etc...).

I went through different experiments, trying different existing libs, writing my own solutions etc... I wasn't quite satisfied until I found factory_girl from thoughtbot.

You might not feel the need for a decent fixtures solution if you do a lot of mocking/stubbing, but I recently came back from my "mock everything you can outside of models" approach and I'm getting closer to the mock roles, not objects approach. So, I'm loosing my model/controller testing separation but I'm gaining by not having to maintain "dumb mocks" which don't always represent the real API behind. I mean, how many times did I change a Model, messing up my app but all my specs were still passing. Anyway, that's a long discussion, which will be covered by wycats during merbcamp

So here is a simple example of how I use factory girl in a Merb + DataMapper app. (you can do the same in a Rails app, there is nothing specific to Merb in factory_girl).

  • I. create an empty app, set the ORM etc...

  • II. git pull and install factorygirl from http://github.com/thoughtbot/factorygirl/tree/master. Or install thoughtbot-factory_girl gem using GitHub gem server.

  • III. create a spec/factories.rb file. (You might prefer to create a folder called spec/factories and add a factory per model)

  • IV. modify spec_helper.rb and add the following

1
2
3

  require 'factory_girl'
  require File.dirname(__FILE__) + '/factories'
  • V. write some specs against a Client model
  • VI. Create the Model
  • VII. create a factory
  • IIX. run your specs

    failing specs

  • IX. fix the model (note that I set dependencies "dm-validations" in my init.rb)

  • X. run the specs

    passing specs

  • XI. add more specs

As you can see, Factory.build(:client) only creates a new instance of the Object, while Factory(:client) creates, saves and loads the instance.

  • XII. get them to pass

Factory Girl makes fixtures simple and clean. Here is another example for creating associations:

Factory Girl also supports sequencing, check out FG read me

In conclusion, Factory Girl is a mature and solid factory solution which will take you less than 15 minutes to get used to. It will offer you loads of flexibility and less frustration than good old yaml fixtures. You can also use it with existing fixtures if you want to start using it in an existing app.


more »

db fixtures replacement solution step by step »

Created at: 07.09.2008 19:06, source: Rails on the Run - Home, tagged: datamapper factory_girl fixtures merb rspec rspec spec testing

Like most people who started with Rails a while back, I first loved Rails fixtures and ended up hating them (slow, a pain to maintain etc...).

I went through different experiments, trying different existing libs, writing my own solutions etc... I wasn't quite satisfied until I found factory_girl from thoughtbot.

You might not feel the need for a decent fixtures solution if you do a lot of mocking/stubbing, but I recently came back from my "mock everything you can outside of models" approach and I'm getting closer to the mock roles, not objects approach. So, I'm loosing my model/controller testing separation but I'm gaining by not having to maintain "dumb mocks" which don't always represent the real API behind. I mean, how many times did I change a Model, messing up my app but all my specs were still passing. Anyway, that's a long discussion, which will be covered by wycats during merbcamp

So here is a simple example of how I use factory girl in a Merb + DataMapper app. (you can do the same in a Rails app, there is nothing specific to Merb in factory_girl).

  • I. create an empty app, set the ORM etc...

  • II. git pull and install factorygirl from http://github.com/thoughtbot/factorygirl/tree/master. Or install thoughtbot-factory_girl gem using GitHub gem server.

  • III. create a spec/factories.rb file. (You might prefer to create a folder called spec/factories and add a factory per model)

  • IV. modify spec_helper.rb and add the following

1
2
3

  require 'factory_girl'
  require File.dirname(__FILE__) + '/factories'
  • V. write some specs against a Client model
  • VI. Create the Model
  • VII. create a factory
  • IIX. run your specs

    failing specs

  • IX. fix the model (note that I set dependencies "dm-validations" in my init.rb)

  • X. run the specs

    passing specs

  • XI. add more specs

As you can see, Factory.build(:client) only creates a new instance of the Object, while Factory(:client) creates, saves and loads the instance.

  • XII. get them to pass

Factory Girl makes fixtures simple and clean. Here is another example for creating associations:

Factory Girl also supports sequencing, check out FG read me

In conclusion, Factory Girl is a mature and solid factory solution which will take you less than 15 minutes to get used to. It will offer you loads of flexibility and less frustration than good old yaml fixtures. You can also use it with existing fixtures if you want to start using it in an existing app.


more »