I'm trying to clean up my test suite and to make this easier I'd like to have rspec raise an error when ever it encounters a warning. Rather then pass the test and carry on, I'd like the test to fail. Is there a way I can configure rspec to do this?
Are you talking about deprecation warnings? Or warnings in general?
I know you can raise errors when you hit deprecation warnings by setting config.active_support.deprecation = :raise in your test.rb
Per the RubyDoc for RSpec on Method: RSpec::Matchers#output, you should be able to fail the test by using expect(method).to_not output.to_stdout. I'm no expert in using RSpec, but in theory that should work. RSpec-Puppet has a very similar functionality built in that fails on warnings by using Puppet.expects(:warning).never .
I'm not sure this will work everywhere, since there is no contract that warnings have to be issued through Logger#warn, but this might do a decent job.
class Logger
def warn(*args)
super
if Rails.env.test?
raise(RuntimeError, "failing upon warn")
end
end
end
log = Logger.new
log.warn("foo")
Rspec gives us a simple way to do this globally:
config.before do
expect_any_instance_of(Logger).to_not receive(:warn)
end
Related
We have a RoR application, Rspec for tests with Webmock for HTTP requests.
After having to do some refactoring in our legacy codebase, I realized that many of our tests had unnecessary stubs.
Like this example, the do_a function has been refactored so that we don't do any api call so the stub_request is not necessary anymore, worse, it should be removed.
it 'does something' do
stub_request(:get, 'http://something.com/users/123')
do_a
expect(..)
end
One way of fixing this is:
it 'does something' do
stub_something = stub_request(:get, 'http://something.com/users/123')
do_a
expect(..)
expect(stub_something).to have_been_requested.once
end
But I'd like to enforce this directly through a strict mode where the test fails if any declared stub has not been called ? The first example would then fail automatically.
Thanks a lot for your help
You want to use expectations instead of stub_request:
expect(WebMock).to have_requested(:get, "http://something.com/users/123").once
# or
expect(a_request(:get, "http://something.com/users/123")).to have_been_made.once
But I'd like to enforce this directly through a strict mode where the test fails if any declared stub has not been called?
I don't think this is really possible unless you do some heavy monkeypatching - and it seems like a bad idea instead of just refactoring your tests.
Is it deliberate? I mean the output message says something along the lines of
If you need more of the backtrace for any of these deprecations you can
configure `config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.
I guess nobody has ever contemplated a potentially more realistic prospect, based on the thousands of views these questions have been getting?
If you would prefer not to receive these friendly warnings configure
`Config.no_more_warnings_please_thanks_all_the_same`
I've tried
To disable warnings when running rake test add $VERBOSE=nil into your spec/spec_helper.rb
And
ActiveSupport::Deprecation.behavior = :silence
and
ActiveSupport::Deprecation::DEFAULT_BEHAVIORS[:silence] = Proc.new {|message, callstack| }
I even put it before the
Bundler.require(*Rails.groups)
Numerous expressions of concern appear that some may not understand the gravity of the situation. i.e.
"It's not good to ignore warnings. You should be reading all of them......"
Any ideas? Surely someone has worked it out. Someone from the Rspec community possibly?
I would like to suppress all warnings actually. Not that I would be ignoring them of course. But if I'm just making some simple reluctant edit to a paying clients legacy product I don't think it is fair on them to have to spend time and money on dealing with warnings.
I'm not very experienced at programming as is evident from my reputation points so please sympathise with my frustration.
--Use with caution--
First off, generic warning about removing warnings.
Secondly, this is what I did. In the RSpec.configure block, add the following lines of code.
config.before(:all, silent: true) do
#with_warnings = $VERBOSE
$VERBOSE = nil
end
config.after(:all, silent: true) do
$VERBOSE = #with_warnings
end
I put this in the rails_helper. On the describe blocks that I don't want returning warnings, I tag them with silent: true.
describe "Is foo bar?", silent: true do
# testing all the things
end
That will suppress EVERYTHING, including warnings about constants and undefined variables. The results of the test will still be intact and will let you know that foo, in fact, does not equal bar.
--Use with caution--
My Rails 4/Ruby 2 app is throwing the following warning every time my RSpec tests create a FactoryGirl object: "DEPRECATION WARNING: This dynamic method is deprecated. Please use e.g. Post.find_or_create_by(name: 'foo') instead."
This warning is not thrown when I run my app in development. Is FactoryGirl's code throwing this? I tried to find some information but it doesn't look like other people are getting this.
If you tell Rails to give you a full stack trace for the deprecation warning, you should be able to diagnose it pretty easily. The warnings are coming from a library called ActiveSupport::Deprecation - tell it to run in debug mode.
# config/environments/test.rb
ActiveSupport::Deprecation.debug = true
For me, the warnings were caused by an old version of the Stringex library.
FactoryGirl would make a new model, which would trigger a call to one of the Stringex methods, which would raise the warning, although there was no way to see that until I turned on full stack traces. bundle update stringex solved the issue with no problem.
It looks like it's coming from ActiveRecord.
module DeprecationWarning
def body
"#{deprecation_warning}\n#{super}"
end
def deprecation_warning
%{ActiveSupport::Deprecation.warn("This dynamic method is deprecated. Please use e.g. #{deprecation_alternative} instead.")}
end
end
I'm not sure why you're not getting the warnings in development. Is your environment suppressing the warnings?
In my Rails application, I have a set of cucumber acceptance tests that test various pages of my application. With cucumber, tagging a specific test (scenario) with #javascript causes that scenario to run using a JavaScript driver instead of a simpler driver that does not support JavaScript.
Is there an easy way for my tests to determine whether they are currently being run with a driver that supports JavaScript or one that doesn't? I want this so that I can make my tests behave slightly differently if they are being run with JavaScript enabled.
In case anyone's interested, I took a look at the documentation for Capybara and found another possible solution:
if Capybara.current_driver == Capybara.javascript_driver
# Supports JavaScript
else
# Doesn't support JavaScript
end
It's kind of obnoxious, but this is what I landed on. Think I got it from a gist somewhere, sorry I lost the link to it but at least it's pretty straightforward:
def javascript_test?
[:selenium, :webkit, :chrome, :poltergeist].include?(Capybara.current_driver)
end
If you define (or require in your Gemfile) other js enabled drivers, you'd have to add them to this list.
Looks to me from this answer like the easiest way to do this is to set an instance variable in a Before hook:
Before('#javascript') do
#javascript = true
end
Then you can test if a scenario is tagged in step definitions by checking the value of that instance variable:
When /^I go to the homepage$/ do
if #javascript
...
else
...
end
end
I've tested this and it seems to work.
You could also simply probe for the capability and rescue any exception. This is probably the most precise and compatible approach:
def support_js?
return #support_js unless #support.nil?
#support_js = begin
page.evaluate_script("1 + 1")
true
rescue Capybara::NotSupportedByDriverError => _err
false
end
end
Similar to the problem described here:
http://rpheath.com/posts/411-how-to-use-factory-girl-with-rspec
in Short (shorten'd code):
spec_helper:
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
factories.rb:
Factory.define :state do
f.name "NY"
end
in my spec
before(:each) do
#static_model = Factory(:state) # with validate uniqueness of state name
end
error:
duplicate entry name "NY" etc.
Question:
Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
Things i think off:
do you use rake spec to run your testsuite: that builds up the database from scratch (to make sure nothing is sticking)
do you use, anywhere, a before (:all) ? Because whatever you create inside a before :all should be deleted again in a after :all or it keeps on existing.
Question: Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
RSpec with DatabaseCleaner or RSpec Rails with use_transactional_fixtures will clear the DB as long as your created the data in the example itself. before :all do ... end is considered outside of the example, because the data remains untouched across multiple examples. Whatever you create in before :all you have to delete in after :all.
In order to delete whatever you create automatically use before :each do ... end. Be aware the same data will be created and removed 10 times if you have 10 examples. The difference between before :all and before :each is better explained here: rails rspec before all vs before each
Some more possible causes:
There's still a states.yml fixture sitting around
Someone played around on script/console test and forgot to clean up afterwards.
You might also find it's because you haven't wrapped the statement in:
describe "what it should do" do
#static_model = Factory(:state) # with validate uniqueness of state name
end
I discovered that was the change that solved this problem:
Why isn't factory_girl operating transactionally for me? - rows remain in database after tests
I have had similar questions about what sort of starting state one can expect when using FG and RSpec.
While I too wait for clarity, Database Cleaner could be a good fix: http://rubydoc.info/gems/database_cleaner/0.6.7/frames
hth -
Perry
When you use Factory(:state) wich is a shortcut to Factory.create(:state), factory_girl returns you a saved object.
Use Factory.build(:state) instead.
Dude maybe your yaml fixtures from regular unit tests get mixed into your rspec?