Rails: Good Rspec2 Example Usage? (Also: Cucumber, Pickle, Capybara)

Best way to fill development db in rails

Faker is also a good solution.

Here's how my lib/tasks/sample_data.rake looks like. I run it with rake db:populate.

Creates 50 entries with random info.

require 'faker'

namespace :db do
desc "Fill database with sample data"
task :populate => :environment do
Rake::Task['db:reset'].invoke
50.times do |n|
name = Faker::Company.name
year = 1900+rand(111)
rating = 1+rand(10)
watched = (1 == rand(2) ? true : false)
imdb_id = rand(1000000)
Movie.create!(:name => name,
:year => year,
:rating => rating,
:watched => watched,
:imdb_id => imdb_id)
end
end
end

shoulda macros with rspec2 beta 5 and rails3 beta2

Using RSpec 2.0.0.beta.19

# Gemfile
group :test do
gem "rspec", ">= 2.0.0.beta.19"
gem "rspec-rails", ">= 2.0.0.beta.17"
gem "shoulda"
end

# spec/spec_helper.rb
require 'rspec/rails'
require 'shoulda/integrations/rspec2' # Add this line

# In your specs....
it { should validate_presence_of(:name) }

Running rake spec should now load and run specs including the RSpec 2 matchers.

Can an RSpec scenario example only have one assertion?

Your spec (= feature) only has one example (= scenario). That example has three expectations (= assertions). (You may want to edit your title and question to clarify the terminology.) When an expectation in an example fails, it raises an exception, and subsequent expectations never get a chance to run. That's just the way RSpec works. (It has nothing to do with whether you're using Capybara.) It's not a big deal if this behavior hides that one of the subsequent expectations would have failed; you'll find out as soon as you fix the first one and run the example again.

I recommend writing specs in the way that you have. Writing a separate spec for every expectation results in harder-to-read specs, because rspec's DSL was not designed to write specs efficiently or clearly with only one expectation per spec, and it results in more examples which makes your test suite slower.

Side note: Capybara's have_content and have_text are the same, so you only need one of those expectations.

Using RSpec to test for correct order of records in a model

In your code:

it "should have the right emails in the right order" do
Email.should == [@email_newest, @email]
end

You are setting the expectation that the Email model should be equal to the array of emails.
Email is a class. You can't just expect the class to be equal to an array. All emails can be found by using all method on class Email.

You must set the expectation for two arrays to be equal.

it "should have the right emails in the right order" do
Email.order('created_at desc').all.should == [@email_newest, @email]
end

It should work like this.

Repeated test descriptions with RSpec for every user role

describe "GET 'index'" do
User::ROLES.each do |role|
context "for #{role} user" do
login_user(role)

it "has the right title" do
response.should have_selector("title", :content => "the title")
end
end
end
end

You can use ruby's iterators in your specs. Given your particular implementation you'll have to adjust the code, but this give you the right idea for DRY'ing out your specs.

Also you'll need to make the necessary adjustments so your specs read well.

When to use RSpec let()?

I always prefer let to an instance variable for a couple of reasons:

  • Instance variables spring into existence when referenced. This means that if you fat finger the spelling of the instance variable, a new one will be created and initialized to nil, which can lead to subtle bugs and false positives. Since let creates a method, you'll get a NameError when you misspell it, which I find preferable. It makes it easier to refactor specs, too.
  • A before(:each) hook will run before each example, even if the example doesn't use any of the instance variables defined in the hook. This isn't usually a big deal, but if the setup of the instance variable takes a long time, then you're wasting cycles. For the method defined by let, the initialization code only runs if the example calls it.
  • You can refactor from a local variable in an example directly into a let without changing the
    referencing syntax in the example. If you refactor to an instance variable, you have to change
    how you reference the object in the example (e.g. add an @).
  • This is a bit subjective, but as Mike Lewis pointed out, I think it makes the spec easier to read. I like the organization of defining all my dependent objects with let and keeping my it block nice and short.

A related link can be found here: http://www.betterspecs.org/#let



Related Topics



Leave a reply



Submit