Why Should I Use Rspec or Shoulda with Rails

Why should I use RSpec or shoulda with Rails?

RSpec and similar frameworks are tooling designed to aid in Behavior Driven Development. They're not just a prettier way to write tests, though they do help with that.

There is plenty of information on BDD here: http://behaviour-driven.org/
And wikipedia: http://en.wikipedia.org/wiki/Behavior_Driven_Development

There are too many benefits to list here, so I'd recommend browsing that site a little.

RSpec vs. Shoulda?

RSpec has a lot of nice features, more than just the syntax too. I would recommend it over Shoulda.

Even Thoughtbot, the authors of Shoulda, are using RSpec now. Shoulda now works as an RSpec plugin and it provides a number of useful matchers.

rspec and shoulda - complementary or alternatives?

I have to argue against Chris's answer that they are alternatives. I use Shoulda and Rspec together in my Rails application, and they complement each other well.

This combo allows me to write concise one-line unit tests for recurring things like associations and validations, as well as the having the full rspec suite for more complex specs. You get the best of both worlds without any conflicts.

Check out the Shoulda README which shows how to install along side Rspec. It even says it provides "Test::Unit- and RSpec-compatible one-liners that test common Rails functionality. These tests would otherwise be much longer, more complex, and error-prone."

Edit (examples):

At the top of my specs, I always declare my Class relationship and validation tests which are concise and easy to read.

describe Component do

context 'relationships' do
it { should belong_to(:technology)}
it { should have_many(:system_components) }
it { should have_and_belong_to_many(:variables) }
it { should have_many(:images).dependent(:destroy) }
it { should have_many(:documents).dependent(:destroy) }
end

context 'validations' do
it { should validate_presence_of(:make) }
it { should validate_presence_of(:model) }
it { should ensure_length_of(:name).is_at_most(100) }
it { should validate_presence_of(:technology_id) }
end
end

Then the rest of my spec will have more complex tests where I am using mocks and stubs which come from Rspec.

rSpec vs Shoulda confusion

Shoulda just adds additional matchers to RSpec.

http://rubydoc.info/github/thoughtbot/shoulda-matchers/master/frames

BDD on Rails - Is the community more behind Shoulda or RSpec?

The rails community is in favor of both RSpec and Shoulda. It depends of the developer.
If you prefer Shoulda, use it.

If you prefer RSpec, use it ;)

They're both different library with a similar goal. It doesn't mean every developer has to be for or against it. It only means that you can use either of them.

It's up to you to make your choice depending of your preferences (and the other developers you're working with).

Using shoulda to refactor rspec tests on Rails models

1) The Shoulda::Matchers::ActiveRecord module has a lot more in it than just column and index matchers. I would dig around in the included classes a little and see what you can find. This is where the have_many, belong_to etc come from. For the record though, I see little value in most of what is in there.

2) Yes, macros such as have_many test a lot more than whether or not a model responds to a method. From the source code, you can see exactly what it is testing:

def matches?(subject)
@subject = subject
association_exists? &&
macro_correct? &&
foreign_key_exists? &&
through_association_valid? &&
dependent_correct? &&
class_name_correct? &&
order_correct? &&
conditions_correct? &&
join_table_exists? &&
validate_correct?
end

3) Making the tests more readable and/or concise is definitely a subjective question to answer. Everyone will give you a different answer to this depending on their background and experience. I would personally get rid of all of the respond_to tests and replace them with tests that have value. When someone looks at your tests, they should be able to understand the public API for that class. When I see that your objects respond_to something like "following?", I can make assumptions, but don't really know what it means. Does it take an argument? Does it return a boolean value? Is the object following something or is something following the object?

testing with rspec + shoulda-matchers

It looks good to me - here is a further example taking a class Listing that tests both the associations and validations.

class Listing < ActiveRecord::Base

#Associations
belongs_to :user
belongs_to :category, inverse_of: :listings
has_many :photos, dependent: :destroy
has_many :watches
has_many :watchers, -> { uniq }, :through => :watches
has_many :offers, dependent: :destroy
has_many :feedbacks
belongs_to :location, :dependent => :destroy

# Association validations
validates_presence_of :category
validates_presence_of :user

# Attribute validations
validates_presence_of :title, message: "Please add a title."
validates_presence_of :subtitle, message: "Please add a subtitle."
validates_presence_of :price, message: "Please add a price."
validates_presence_of :title, message: "Please select a condition."

require 'rails_helper'

RSpec.describe Listing, type: :model do

#Associations
it { should belong_to(:user) }
it { should belong_to(:category) }
it { should have_many(:photos) }
it { should have_many(:watches) }
it { should have_many(:watchers).through(:watches) }
it { should have_many(:offers) }
it { should belong_to(:location).dependent(:destroy) }

#Association validations
it { should validate_presence_of(:category) }
it { should validate_presence_of(:user) }

#Attribute validations
it { should validate_presence_of(:title).with_message("Please add a title.") }
it { should validate_presence_of(:subtitle).with_message("Please add a subtitle.") }
it { should validate_presence_of(:price).with_message("Please add a price.") }
it { should validate_presence_of(:title).with_message("Please select a condition.") }

Note the use of RSpec.describe Class, type: :model to specify the type of tests.

I would read the Shoulda readme that explains more about the availability of matchers in various example groups. They provide four categories of matchers:

ActiveRecord and ActiveModel matchers are available only in model
example groups, i.e., those tagged with type: :model or in files
located under spec/models.

ActionController matchers are available only in controller example
groups, i.e., those tagged with type: :controller or in files located
under spec/controllers.

The route matcher is available also in routing example groups, i.e.,
those tagged with type: :routing or in files located under
spec/routing.

Independent matchers are available in all example groups.


In terms of arranging your specs aim to mirror your app directory (more or less).

So if you have:

app/models/user.rb
app/services/
app/controllers/
app/presenters/

You can mirror this with:

spec/models/user_spec.rb
spec/services/
spec/controllers/
spec/presenters/

You may then have some additional spec folders such as:

spec/features/ (a folder for integration/feature specs)

The RSpec documentation has some very good info on this.

Shoulda-helpers - Rspec

Did you add following in your rails_helper.rb?

Shoulda::Matchers.configure do |config|
config.integrate do |with|
# Choose a test framework:
with.test_framework :rspec

# Choose one or more libraries:
with.library :rails
end
end

Further, why you do you have require false?, you should remove require false from your gemfile.
GEMFILE:

 group :development, :test do
gem 'byebug'
gem "sqlite3"
gem "rspec-rails"
gem "capybara"
gem "factory_girl_rails"
gem "simplecov", require: false
gem "shoulda-matchers", require: false
end

rspec shoulda matchers is expected to belong to polymorphic

The issue seems to be:

and for the record to fail validation if :bar is unset;

Since, you have optional: true - this part is not satisfied.

It looks like shoulda assumes a relation should be required, unless you tell it otherwise.

Try modifying this matcher like so

it { is_expected.to belong_to(:bar).optional }

https://github.com/thoughtbot/shoulda-matchers/blob/master/lib/shoulda/matchers/active_record/association_matcher.rb#L304:L321



Related Topics



Leave a reply



Submit