Get Integrity to play well with Rails 3 and Bundler 1.0

The latest “stable” version of Integrity (v22) doesn’t play well with Rails 3 (or any other application using bundler 1.0). Basically the Integrity’s Gemfile is used in place of the application’s Gemfile when running the tests.

With a Rails 3 application you are likely to get:

no such file to load -- rails/all

Integrity fails to run with Rails 3 and Bundler 1.0

A patched version of integrity v22 for bundler 1.0 is available on http://github.com/pcreux/integrity/tree/v22-bundler-1.0.0.rc.

You also need to force your Rails application to use its Gemfile. To do so, update the file /config/boot.rb with the following:

require 'rubygems'
# Set up gems listed in the Gemfile.
GEMFILE_PATH = File.expand_path('../../Gemfile', __FILE__)
if File.exist?(GEMFILE_PATH)
  # Force the rails 3 application to use its Gemfile
  ENV['BUNDLE_GEMFILE'] = GEMFILE_PATH
  require 'bundler'
  Bundler.setup
end

That should make the trick!
Patched Integrity and custom boot.rb makes integrity working with Rails 3

Leave a comment

Speed up RSpec with set()

I enjoy using the let() method as it makes my specs easier to read and maintain than setting up instance variables in before(:each) blocks. The let() method can be used like this:

describe Account do
  let(:account) { Factory(:account) }

  subject { account }

  it { should be_enabled }

  context "when #disable!" do
    before do
      account.disable!
    end

    it { should be_disabled }
  end
end

My main concern was that the block gets evaluated everytime the method is called. In the example above, Factory(:account) will run and create a new record for every single spec.

To increase our specs performances let’s refactor this and setup the account in a before(:all) block.

describe Account do
  before(:all) do
    @account = Factory(:account)
  end

  let(:account) { @account.reload }
  #...
end

The account is now setup once before the specs get run. Each spec will be run in a separate transaction to prevent side effects. The account will be rolled back to its initial state before each spec then. Since ActiveRecord is not aware of the rollback we reload the account object from the database every time it’s called.

Specs are now faster but I want them to be as pretty as they were. Let’s make a little helper called set().

Sweeeet! You can now write the following:

describe Account do
  set(:account) { Factory(:account) }

  #...
end

The records created by set() will remain in your database. You can use DatabaseCleaner with the :truncation strategy to clean up your database. So far in RSpec 2.0, before(:all) runs before all describe/context/it while after(:all) runs after every single describe/context/it. Just make sure that you call DatabaseCleaner.clean in a before(:all) or after(:suite) blocks then. :)

I hope you’ll enjoy using this little helper. It’s very young and it has been tested with RSpec 2 only, so fill free to fill up the comments with enhancements and bug reports!

Edit: Fix for rspec 2.0.0.beta.17.

6 Comments

Get script/runner back in Rails 3

EngineYard’s chef recipe for DelayedJob requires script/runner. To use this recipe with Rails 3 I’ve just made script/runner for Rails 3. Here is the code:

Edit: Fix for rails 3.0

2 Comments

(My) RSpec best practices and tips

After a year using RSpec, I’m happy to share “(My) RSpec Best Practices and Tips”. Let’s make your specs easier to maintain, less verbose, more structured and covering more cases!

Use shortcuts specify {}, it {} and subject {}

You think RSpec is verbose? In case your code doesn’t need any description, use a specify block!

it "should be valid" do
  @user.should be_valid
end

can be replaced with

specify { @user.should be_valid }

RSpec will generate a nice description text for you when running this expectation. Even better, you can use the it block!

describe User do
  it { should validate_presence_of :name }
  it { should have_one :address }
end

In case the subject is the not the class described, just set it with the subject method:

subject { @user.address }
it { should be_valid }

Start context with ‘when’/'with’ and methods description with ‘#’

Have you ever get a failed test with an incomprehensible error message like:

User non confirmed confirm email wrong token should not be valid

Start your contexts with when and get nice messages like:

User when non confirmed when #confirm_email with wrong token should not be valid

Use RSpec matchers to get meaningful messages

In case of failure

specify { user.valid?.should == true }

displays:

'User should == true' FAILED
  expected: true,
  got: false (using ==)

While

specify { user.should be_valid }

displays:

'User should be valid' FAILED
  expected valid? to return true, got false

Nice eh?

Only one expectation per it block

I often see specs where it blocks contain several expectations. This makes your tests harder to read and maintain.

So instead of that…

describe DemoMan do
  it "should have expected attributes" do
    demo_man = DemoMan.new
    demo_man.should respond_to :name
    demo_man.should respond_to :gender
    demo_man.should respond_to :age
  end
end

… do this:

describe DemoMan do
  before(:all) do
    @demo_man = DemoMan.new
  end

  subject { @demo_man }

  it { should respond_to :name   }
  it { should respond_to :gender }
  it { should respond_to :age    }
end

(Over)use describe and context

Big specs can be a joy to play with as long as they are ordered and DRY. Use nested describe and context blocks as much as you can, each level adding its own specificity in the before block.
To check your specs are well organized, run them in ‘nested’ mode (spec spec/my_spec.rb -cf nested).
Using before(:each) in each context and describe blocks will help you set up the environment without repeating yourself. It also enables you to use it {} blocks.

Bad:

describe User do

  it "should save when name is not empty" do
    User.new(:name => 'Alex').save.should == true
  end

  it "should not save when name is empty" do
    User.new.save.should == false
  end

  it "should not be valid when name is empty" do
    User.new.should_not be_valid
  end

  it "should be valid when name is not empty" do
    User.new(:name => 'Alex').should be_valid
  end

  it "should give the user a flower when gender is W" do
    User.new(:gender => 'W').present.should be_a Flower
  end

  it "should give the user a iMac when gender is M" do
    User.new(:gender => 'M').present.should be_an IMac
  end
end

Good:

describe User do
  before { @user = User.new }

  subject { @user }

  context "when name empty" do
    it { should not be_valid }
    specify { @user.save.should == false }
  end

  context "when name not empty" do
    before { @user.name = 'Sam' }

    it { should be_valid }
    specify { @user.save.should == true }
  end

  describe :present do
    subject { @user.present }

    context "when user is a W" do
      before { @user.gender = 'W' }

      it { should be_a Flower }
    end

    context "when user is a M" do
      before { @user.gender = 'M' }

      it { should be_an IMac }
    end
  end
end

Test Valid, Edge and Invalid cases

This is called Boundary value analysis, it’s simple and it will help you to cover the most important cases. Just split-up method’s input or object’s attributes into valid and invalid partitions and test both of them and there boundaries. A method specification might look like that:

describe "#month_in_english(month_id)" do
  context "when valid" do
    it "should return 'January' for 1" # lower boundary
    it "should return 'March' for 3"
    it "should return 'December' for 12" # upper boundary
  context "when invalid" do
    it "should return nil for 0"
    it "should return nil for 13"
  end
end

I hope this will help you improve your specs. Let me know if I missed anything! :)

34 Comments

Migrate Rubygems to Ruby Enterprise Edition (REE)

If you have a server running the default Ruby interpreter (“Matz’s Ruby Interpreter” or “Ruby MRI”) and you want to switch to Ruby Enterprise Edition (REE) the following script will help you migrating the gems.

Once you have installed Ruby Enterprise Edition run this script so that REE installs the gems installed on your default ruby environment.

That’s all folks!

Leave a comment

Move your Ubuntu system to another computer in 3 simple steps

You just got a brand new machine but you won’t like to spend hours tuning it to get the same configuration as the one you have used for years?

Let’s transfer your Ubuntu configuration and applications to your new computer in three simple steps.

This method is cross-architecture. I moved successfully my configuration and applications from an Ubuntu 9.04 32bit to a 64bit one.

Prerequisites:

The same version of Ubuntu is installed on both machines. The architecture (32/64 bit) can be different.

Step 1: Store the list of installed packages

Run the following command on the source machine to store the installed packages names in ~/pkglist:
sudo dpkg --get-selections | sed "s/.*deinstall//" | sed "s/install$//g" > ~/pkglist

Step 2: Transfer your config

Use scp or rsync or even a flash drive to transfer your home directory (~/*, ~/.*), the source list (/etc/apt/sources.list) and any other files you customized or installed (like apache config under /etc or softwares on /opt) from the source machine to the target one.

Step 3: Install packages

On the target machine run the following command in a failsafe terminal session to install your packages:

sudo aptitude update && sudo aptitude install `xargs ~/pkglist`

That’s all folks!

Log into your new machine and keep working as if you were using the previous one.

A freshly transfered Ubuntu install

4 Comments

Jabber-SH — SH console via XMPP/Jabber (GTalk)

Screenshot-Jabber-SH on GTalk

I’ve just posted the code of Jabber-SH on GitHub. Jabber-SH is a ruby hack that allows you to administrate a remote computer via a command line through a Jabber client. It’s like SSH via GoogleTalk! :)

I coded it nine month ago then I planned to add some specs, to store the configuration in a yaml file, to make a gem out of it but… I didn’t and I won’t get a chance to do that. So here are the 25 lines of code… hackish eh?!

3 Comments

Top-down and Bottom-up programming illustrated by Mac OS X and Windows

Bottom-up programming starts by developing the data model before designing the user interface. Windows Start/Programs menu illustrates this approach. Since programs shortcuts are stored in the directory Programs the menu displays the content of this directory.

Windows XP Start menu

Top-down programming starts by designing the user interface before developing the data model. Mac OS X dock illustrates this approach. As it should be easy for a user to launch an application the dock displays big icons accessible in one click.

Mac OS X Dock

2 Comments

Back to VIM for Ruby and Rails

I learned to use VIM at the university to administrate linux systems and to develop C++ apps. Then I moved to Java and I enjoyed using an IDE like Netbeans. When I started to play with Ruby and Rails I kept using Netbeans as my editor of choice as it plays very well with them.

As I was bored with “Up arrow key, End key, Enter key” instead of “O” to insert a new line above my cursor and I wanted to play again with this so old but still alive editor, I installed the plugins: rails.vim (just great), haml syntax highlight (I ♡ haml) and irblack color scheme (more Textmate like).

With rails.vim, you get just great shortcuts to browse your rails source file. Type :Rmodel your_model_name to edit your model source file — :Rcontroller, :Rview, :Rmigration, :Rjavascript, :Rstylesheet… work too! It also includes :A (jump to alternate file) and :R (jump to relative file) commands. :A switches between source code and corresponding spec file, :R jumps from model to migration file. The most amazing combo: :AV to open up the alternative file (your spec file usually) in a vertical split window.

I finish up with the two commands I learned to use and love.1) Type ma to “mark” your cursor position as ‘a’ then type 'a to get back to this position. 2) Use qa to record a macro in ‘a’, press q again to stop recording. Then @a to replay it. Using commands to jump to next word / end of line / next something character it can be much faster than making a substitution using regexp or so.

3 Comments

How-to make the front mic working on Ubuntu 9.10 (Dell laptop: Intel Hda soundcard)

Ubuntu 9.10 comes with alsa 1.0.20 allowing the front mic to work on a Dell XPS M1530. From the Sound Preferences, select Microphone 2 then fire up a terminal, launch alsamixer -V capture and set the following options and enjoy!

Screenshot-AlsaMixer

Leave a comment