How to check for failures in an RSpec test suite?
I poked around in the RSpec source code and figured out that the following would work. Just put this code in spec_helper.rb
or some other file that gets loaded when you run the tests:
RSpec.configure do |config|
config.after(:suite) do
examples = RSpec.world.filtered_examples.values.flatten
if examples.none?(&:exception)
# change the seed here
end
end
end
The RSpec.world.filtered_examples
hash associates example groups to an array of examples from that group. Rspec has features for filtering out certain examples, and this hash appears to only contain the examples that were actually run.
One alternative way you could set up your system would be to check the return code of the rspec process. If it is 0, then all the tests passed and you can change the seed.
In a shell script, you could define a command that changes the seed and run:
rspec && change_seed
If your project has a Rakefile, you could set up something like this:
task "default" => "spec_and_change_seed"
task "spec" do
sh "rspec spec/my_spec.rb"
end
task "spec_and_change_seed" => "spec" do
# insert code here to change the file that stores the seed
end
If the specs fail, then rake's "spec" task will fail and it will not go on to change the seed.
What could cause RSpec to fail when a controller test sees a view file with a _path helper only when when running the entire suite
Oh wow, so in one of our test files someone (normally git blame points fingers at me, strangely not this time!!) had added
include Rails.application.routes.url_helpers
Which presumably has changed between 6.0 and 6.1 so including this file does something.
Unlike other tests I've seen fail based on the order they ran, because this sits at the top of a file, no order would pass so long as RSpec loaded in the file.
tl;dr, don't include url_helpers in your test this way!
How to force an RSpec test to fail?
fail
/raise
will do the trick (they are aliases of each other).
Example
specify "this test fails" do
raise "this is my failure message"
end
Fails with:
1) failing this test fails
Failure/Error: raise "this is my failure message"
RuntimeError:
this is my failure message
Alternatives
If you are thinking of using raise
/fail
in a spec, you should consider that there are probably more explicit ways of writing your expectation.
Additionally, raise
/fail
doesn't play well with aggregate_failures
because the exception short-circuits the block and won't run any following matchers.
Mark a test as pending
If you need to mark a test as pending to make sure you get back to it, you could use the fail
/raise
, but you can also use pending
.
# Instead of this:
it "should do something" do
# ...
raise "this needs to be implemented"
end
# ✅ Try this:
it "should do something" do
pending "this needs to be implemented"
end
Assert that a block is not called
If you need to ensure a block is not being executed, consider using the yield
matchers. For example:
describe "Enumerable#any?" do
# Instead of this:
it "doesn't yield to the block if the collection is empty" do
[].any? { raise "it should not call this block" }
end
# ✅ Try this:
it "doesn't yield to the block if the collection is empty" do
expect { |b| [].any?(&b) }.not_to yield_control
end
end
Failing (previously passing) RSpec test even after commiting back
It could be that your Test DB is not being cleaned. Try running rails c test
and query Product.count
to see if the Test DB has the product records which may be causing this error. You can also put a byebug
or puts Product.count
in your before(:each) block before using the factory to create records to ensure that there ain't no existing records before running the tests. If that's the case, you'll need to clean your DB before and after tests manually or by the DatabaseCleaner Gem.
Tip:
It's also better to use a variable for the number of records you're creating and expecting.
Example:
products_count = 4.times { FactoryGirl.create :product }
expect(products_response).to have(products_count).items
Rspec tests fail even though everything works fine manually
You need to reload your user
object, via user.reload.friend_requests
. The in-memory object in your test hasn't been hydrated with any updates.
RSpec - Check if method was called further down(up?) the call stack
RSpec allows you to use the any_instance_of
set of matchers for setting this up.
This can be useful if you need to do this particular type of test and can't manually specify the instances via DI.
expect_any_instance_of(Widget).to receive(:name).and_return("Wobble")
See here
Related Topics
How to Make a Gemset in Rvm the Default
Rails 5 Actioncontroller::Invalidauthenticitytoken Error
Jruby: Import VS Include VS Java_Import VS Include_Class
How to Convert a JSON String to an Object
Share Models Between 2 Rails API's (Separate Applications)
How to Extract the Sign of an Integer in Ruby
How to Access Class Variables in Ruby 1.9
Ruby on Rails: How to Check If a File Is an Image
How to Validate the Presence of a Belongs to Association with Rails
Creating a Hash with Values as Arrays and Default Value as Empty Array
Are There Better Ways to Prevent 'Yield' When No Block Is Passed In
Missing a Template for This Request Format and Variant
Weird Rails Error "Permission Denied: Bin/Rails" for Old Rails Apps
Make: /Usr/Bin/Mkdir: Command Not Found During 'Gem Install Nokogiri' in Ubuntu 20.04