Difference between an it block and a specify block in RSpec
The methods are the same; they are provided to make specs read in English nicer based on the body of your test. Consider these two:
describe Array do
describe "with 3 items" do
before { @arr = [1, 2, 3] }
specify { @arr.should_not be_empty }
specify { @arr.count.should eq(3) }
end
end
describe Array do
describe "with 3 items" do
subject { [1, 2, 3] }
it { should_not be_empty }
its(:count) { should eq(3) }
end
end
RSpec: What is the difference between let and a before block?
People seem to have explained some of the basic ways in which they differ, but left out before(:all)
and don't explain exactly why they should be used.
It's my belief that instance variables have no place being used in the vast majority of specs, partly due to the reasons mentioned in this answer, so I won't mention them as an option here.
let blocks
Code within a let
block is only executed when referenced, lazy loading this means that ordering of these blocks is irrelevant. This gives you a large amount of power to cut down on repeated setup through your specs.
One (extremely small and contrived) example of this is:
let(:person) { build(:person) }
subject(:result) { Library.calculate_awesome(person, has_moustache) }
context 'with a moustache' do
let(:has_moustache) { true }
its(:awesome?) { should be_true }
end
context 'without a moustache' do
let(:has_moustache) { false }
its(:awesome?) { should be_false }
end
You can see that has_moustache
is defined differently in each case, but there's no need to repeat the subject
definition. Something important to note is that the last let
block defined in the current context will be used. This is good for setting a default to be used for the majority of specs, which can be overwritten if needed.
For instance, checking the return value of calculate_awesome
if passed a person
model with top_hat
set to true, but no moustache would be:
context 'without a moustache but with a top hat' do
let(:has_moustache) { false }
let(:person) { build(:person, top_hat: true) }
its(:awesome?) { should be_true }
end
Another thing to note about let blocks, they should not be used if you're searching for something which has been saved to the database (i.e. Library.find_awesome_people(search_criteria)
) as they will not be saved to the database unless they have already been referenced. let!
or before
blocks are what should be used here.
Also, never ever use before
to trigger execution of let
blocks, this is what let!
is made for!
let! blocks
let!
blocks are executed in the order they are defined (much like a before block). The one core difference to before blocks is that you get an explicit reference to this variable, rather than needing to fall back to instance variables.
As with let
blocks, if multiple let!
blocks are defined with the same name, the most recent is what will be used in execution. The core difference being that let!
blocks will be executed multiple times if used like this, whereas the let
block will only execute the last time.
before(:each) blocks
before(:each)
is the default before block, and can therefore be referenced as before {}
rather than specifying the full before(:each) {}
each time.
It's my personal preference to use before
blocks in a few core situations. I will use before blocks if:
- I'm using mocking, stubbing or doubles
- There is any reasonable sized setup (generally this is a sign your factory traits haven't been setup correctly)
- There's a number of variables which I don't need to reference directly, but are required for setup
- I'm writing functional controller tests in rails, and I want to execute a specific request to test (i.e.
before { get :index }
). Even though you could usesubject
for this in a lot of cases, it sometimes feels more explicit if you don't require a reference.
If you find yourself writing large before
blocks for your specs, check your factories and make sure you fully understand traits and their flexibility.
before(:all) blocks
These are only ever executed once, before the specs in the current context (and its children). These can be used to great advantage if written correctly, as there are certain situations this can cut down on execution and effort.
One example (which would hardly affect execution time at all) is mocking out an ENV variable for a test, which you should only ever need to do once.
Hope that helps :)
Is there a way in rspec to specify a before block for *all* examples in spec_helper.rb?
You can basically add the following configuration in your spec_helper.rb:
RSpec.configure do |config|
# other configs
config.before(:each) do
# Do something
end
end
Rspec: expect vs expect with block - what's the difference?
As has been mentioned:
expect(4).to eq(4)
This is specifically testing the value that you've sent in as the parameter to the method. When you're trying to test for raised errors when you do the same thing:
expect(raise "fail!").to raise_error
Your argument is evaluated immediately and that exception will be thrown and your test will blow up right there.
However, when you use a block (and this is basic ruby), the block contents isn't executed immediately - it's execution is determined by the method you're calling (in this case, the expect
method handles when to execute your block):
expect{raise "fail!"}.to raise_error
We can look at an example method that might handle this behavior:
def expect(val=nil)
if block_given?
begin
yield
rescue
puts "Your block raised an error!"
end
else
puts "The value under test is #{val}"
end
end
You can see here that it's the expect
method that is manually rescuing your error so that it can test whether or not errors are raised, etc. yield
is a ruby method's way of executing whatever block was passed to the method.
Rspec - Better way to stub a block and test the yielded body
Replace the each
with block.call
or just remove the argument and yield
.
I assume the actual implementation of testBlock
is more complicated, because as-is, just yield
is exactly what you need.
Use RSpec's expect etc. outside a describe ... it block
include ::RSpec::Matchers
class A
include ::RSpec::Matchers
def test
expect('1'.to_i).to eq 1
end
def failed_test
expect('1'.to_i).to eq 2
end
end
A.new.test
# => true
A.new.failed_test
# RSpec::Expectations::ExpectationNotMetError:
# expected: 2
# got: 1
How to focus a specify block with {} in RSpec?
The metadata must be provided as the second argument to describe
, context
, it
or specify
, so you'd need to provide at least a dummy value for the first argument. You also need to use parentheses if you want to express your block with braces.
In other words, you'd have to do something like:
specify('', focus: true) { ... }
or
specify(nil, focus: true) { ... }
See https://relishapp.com/rspec/rspec-core/v/2-14/docs/metadata/user-defined-metadata for examples of using user-defined metadata.
Related Topics
How to Run Selenium (Used Through Capybara) at a Lower Speed
Mountain Lion - Libxml & Nokogiri
Is There an Add_Days in Ruby Datetime
How to Use a Rack Middleware Only for Certain Paths
How to Run Rake Tasks Within My Rails Application
Ruby Koans: Explicit Scoping on a Class Definition Part 2
How to List All Files in an S3 Folder Using Aws-Sdk Gem in Ruby on Rails
Stop Rails Console from Printing Out the Object at the End of a Loop
Creating Signature and Nonce for Oauth (Ruby)
How to Make Nokogiri Not to Convert &Nbsp; to Space
Getting Rails Url Helpers to Automatically Output Https Urls
How to Access Url Helper from Rails Module
Cannot Connect to Remote Db Using Ssh Tunnel and Activerecord
Is Ruby on Rails (Or at Least the Community) Dying
How Many Rails Apps on 1 Heroku Dyno
How to Convert a Comma-Separated String into an Array
Error Installing Gems That Use Native Extensions on Ubuntu, Ruby 1.9.2 via Rvm