Detect Rspec Test Failure on After Each Method

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



Leave a reply



Submit