The Ruby/Rails Life – My Rails 3 Stack – Part 2

Rails Deployment & Testing

There are some really nice tools available for deployment and testing rails. Below is a brief description
of some of the ones I’ve been using with success.

Capistrano

I remember in the early days of my attempts of using Rails back in the 1.x days, the deployment/hosting
story was a bit of a headache, even with Capistrano back then. However things have improved dramatically,
especially with things like Phusion Passenger. Capistrano is still strong too and I’ve
found that it makes deploying Rails apps extremely simple. The ability to make that “one quick change” and redeploy
in seconds is an awesome feeling.

Here is a somewhat annotated example of what my deploy script looks like just to give you a glimpse of what a
Capistrano script looks like (with certain information removed of course). If you’ve never used Capistrano before
then this might look a bit foreign. Again, this is just a taste, but you’ll have to dig in a bit more to really
understand the moving parts here.

Example

/config/deploy.rb

    # just some basic info, including where to grab the code from
    set :application, "My Groovy Rails App"
    set :repository,  "[git repo]"
    set :scm, :git

    # there are some SSH options that i don't fully understand yet... :) 
    default_run_options[:pty] = true
    ssh_options[:forward_agent] = true

    # ex. /var/www/my_groovy_rails_app
    set :deploy_to, "[path]" 

    # just some basic server properties
    role :web, "[server]"                   # Your HTTP server, Apache/etc
    role :app, "[server]"                   # This may be the same as your `Web` server
    role :db,  "[server]", :primary => true # This is where Rails migrations will run

    # configure environment variables to propertly use RVM (Ruby Version Manager) on the server
    # as you can see i'm using Ruby 1.8.7 Enterprise Edition on the server
    set :default_environment, {
      'PATH' => '/home/you/.rvm/gems/ree-1.8.7-2010.01/bin:/home/you/.rvm/gems/ree-1.8.7-2010.01@global/bin:/home/you/.rvm/rubies/ree-1.8.7-2010.01/bin:/home/you/.rvm/bin:$PATH',
      'RUBY_VERSION' => 'ree-1.8.7-2010.01',
      'GEM_HOME'     => '/home/you/.rvm/gems/ree-1.8.7-2010.01',
      'GEM_PATH'     => '/home/you/.rvm/gems/ree-1.8.7-2010.01:/home/you/.rvm/gems/ree-1.8.7-2010.01@global',
      'BUNDLE_PATH'  => '/home/you/.rvm/gems/ree-1.8.7-2010.01'  # If you are using bundler.
    }

    # automatically restarts the app after deployment
    namespace :deploy do
      task :start do ; end
      task :stop do ; end
      task :restart, :roles => :app, :except => { :no_release => true } do
        run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
      end
    end

    # tasks for bundler, which is the new way dependencies are managed in Rails 3
    namespace :bundler do
      task :create_symlink, :roles => :app do
        shared_dir = File.join(shared_path, 'bundle')
        release_dir = File.join(current_release, '.bundle')
        run("mkdir -p #{shared_dir} && ln -s #{shared_dir} #{release_dir}")
      end

      task :bundle_new_release, :roles => :app do
        bundler.create_symlink
        run "cd #{release_path} && bundle install --without test"
      end

      task :lock, :roles => :app do
        run "cd #{current_release} && bundle lock;"
      end

      task :unlock, :roles => :app do
        run "cd #{current_release} && bundle unlock;"
      end
    end

    # the actual task that runs bundler to ensure all dependencies on the server are up to date
    after "deploy:update_code" do
      bundler.bundle_new_release
    end

RSpec 2

A lot of you have probably at least heard of RSpec, with some of you perhaps even using it now. It’s a pretty
awesome testing framework, dare I say, BDD framework. Surprisingly I’ve really only scratched the surface as to
what RSpec is capable of, but it’s a joy to use for sure. So far I’m mainly using it for testing my models and a
little bit of controller testing. However I’m leaning on my higher level Cucumber integration tests for exercising
my controllers for the most part. I also haven’t gotten into mocking all that much yet, which RSpec has support for
as well. Perhaps at some point I’ll get into mocking. This is probably going to get me flamed by the ALT.NET’ers,
but honestly I just haven’t felt the pain in the fact that most of my tests DO in fact hit my local test database.
Perhaps that’s because I’m using MongoDB as my database which is so fast I don’t really notice that much of a
performance hit.

Example

Here’s a brief example of a simple model spec in RSpec.

/spec/models/user_spec.rb

describe User do
  context "first name" do
    it "is required" do
      user = User.new
      user.should_not be_valid
      user.errors[:first_name].first.should == "can't be blank"
    end
  end

  context "email" do
    it "is unique" do
      user1 = User.create!(:email => "abc@123.com")
      user2 = User.new(:email => "abc@123.com")

      user2.should_not be_valid
      user2.errors[:email].first.should == "is already taken"
    end
  end
end

Certainly not an exhaustive example, but it gives you the idea of how a basic spec looks in RSpec. And even this is
not nearly as elegant as I’ve been seeing others show lately. I would highly recommend you watch
@l4rk‘s presentation at the Scottish Ruby Conference on
Pure RSpec. I learned a ton from this presentation
and hope to incorporate some of his tips into my specs soon. Specifically the elegance of “let” and “subject”.

Oh, one more note. I’m using RSpec 2, which is still in the early stages, but works with Rails 3. And I’m
actually running it straight from the master git repo. So, use at your own risk!

Cucumber

I’ve named this cute little guy Larry. If you have kids, then you know why. :) This is a pretty nice way of doing
high level acceptance/integration testing. It’s also the first time I’ve ever thought that ATDD (acceptance test driven
development) is actually achievable. The idea is that you write your “stories” in plain english, preferrably
with your client/customer/product owner using the give/when/then style of syntax. Once written, these stories can be
run through the Cucumber framework where it is parsed and coupled with custom ruby code (some of which you have to
write) to essentially give you executable specifications. Of all the attempts I’ve seen out there to achieve ATDD and
executable specifications, Cucumber really seems to have it nailed the best so far. Writing the stories does take some
getting used to as you do somewhat have to learn to speak the “language” of Cucumber. But after writing your first
couple “features”, as Cucumber calls them, you pretty much get the hang of it.

Example

/features/users/addnewuser.feature

Feature: Add new user
    In order to allow a new user to access the system
    As an admin
    I want to add a new user to the system

    Scenario: New link is clicked from the users page
        Given I am logged in as an admin
        And I am on the users page
        When I follow "New"
        Then I should be on the new user page

    Scenario Outline: Required text fields are blank 
        Given I am logged in as an admin
        And I am on the new user page
        When I fill in "" for ""
        And I press "Save"
        Then I should see an error for ""

        Examples:
            | field_name |
            | First name |
            | Last name  |
            | Email      |
            | Password   |

I have another post written that gives a bit more of an overview of Cucumber with more code examples, so look for that
soon.

Steak

I’ve only started to play around with this one, but it’s a pretty interesting take on acceptance/integration testing.
Unlike Cucumber, it doesn’t use plain text stories. Instead it’s basically just a small wrapper of aliases on top
of RSpec that give you same kinda feel as Cucumber, but without the overhead of the English language. I’m going to
be spiking a bit more with this one as I think it might come in handy for some of my other integration testing needs.
Oh, and gotta love its logo! Beef! It’s what’s for…testing?

factory_girl

Interesting name, very useful tool. You might have guessed that this is a tool to create objects for you. Not a whole
lot to say, but it’s really handy to easily create objects in varying states for testing purposes.

Example

/spec/factories.rb

  # creates a new User model
  Factory.define :user do |u|
    u.first_name 'Bud'
    u.last_name 'Abbott'
    u.email { |x| "#{x.first_name.downcase}.#{x.last_name.downcase}@blah.com" }
    u.password 'secret'
    u.password_confirmation 'secret'
    u.group_ids { [Factory.create(:group, :name => 'Users').id] }
    u.roles ['manager']
  end

You can use this factory in a variety of ways.

  # instantiates the User model only, does NOT save it to the database
  Factory.build(:user) 

  # creates the User model and saves it to the database
  Factory.create(:user) 

  # returns a hash of attributes representing this user
  # useful for testing controllers simulating params or for validation
  Factory.attributes_for(:user) 

  # I haven't really found a use for this one yet
  Factory.stub(:user)

  # You can override specific values if desired
  # This would build the user setting a name
  # of "Lou Costello" instead of the default "Bud Abbott"
  Factory.build(:user, :first_name => "Lou", :last_name => "Costello")

rstakeout

This is a nice little script I got from Geoffrey Grosenbach, of PeepCode fame. I use to automatically run my Cucumber
features and RSpec tests anytime I change a file in my Rails app. I find rstakeout to be a lot simpler to get going than
Autotest/Autospec. It has growl integration too. And yes, I do like my green and red growl notifications. :)

Example (from a terminal)

  rstakeout "cucumber -t @wip"

If I run that in my terminal, it automatically watches all files in my Rails app for changes and runs the command I give
it on each change. In this case, it runs my cucumber features, but only ones I’ve tagged with @wip, meaning ones I’m working
on at the given moment.

I’ve posted a Gist of the rstakeout script I’m using since there has been some confusion over which version to use.

Conclusion

Well I hope that gives you a taste of some of the deployment and testing tools I’m using so far in Rails. I feel like I
still have a ton to learn of course, but so far I’m really enjoying the testing experience that the Ruby language gives
me.

What are your favorite deployment/testing tools in Ruby/Rails? Leave a comment and let me know!

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

This entry was posted in bdd, capistrano, cucumber, deployment, factory_girl, rails, rspec, rstakeout, ruby, steak, testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

3 Responses to The Ruby/Rails Life – My Rails 3 Stack – Part 2

  1. DUDE… why didn’t i know about that type of rspec syntax?! I’ve been doing the simple “describe” and “before” blocks for a really long time… that let stuff and context stuff you’re doing looks awesome! will definitely help clean up my albacore tests with that. :)

  2. @Derick,
    Yeah, I had no idea about the “let” and “subject” keywords either until I saw Larkowski’s presentation. Also need to check out the Shoulda matchers which look pretty handy too.

  3. Joe Ocampo says:

    @derick dude, I added this to RSpec back in 2008? You didn’t read my blog. *sad panda* :-(

    http://www.lostechies.com/blogs/joe_ocampo/archive/2008/02/27/using-context-as-an-example-group-in-rspec.aspx