RSpec 2.14 is released!
Myron Marston
Jul 8, 2013We’ve just released RSpec 2.14. It will be the last 2.x feature release and is a recommended upgrade for all users. We’re getting started on RSpec 3. I’ll be blogging about our plans for RSpec 3 next week, so check back soon :).
Thanks to all the contributors who helped make this RSpec release happen.
Notable New Features
Core: Profiler now profiles example groups, too
RSpec has long had the --profile option for dumping the top N
slowest examples at the end. In RSpec 2.14, this has been enhanced
so that it prints the groups with the largest mean example time.
For example, here’s the output from using --profile 5 on rspec-core’s
suite:
Top 5 slowest examples (0.38945 seconds, 10.8% of total time):
RSpec::Core::Formatters::TextMateFormatter produces HTML identical to the one we designed manually
0.10471 seconds ./spec/rspec/core/formatters/text_mate_formatter_spec.rb:64
::DRbCommandLine --drb-port without RSPEC_DRB environment variable set sets the DRb port
0.07461 seconds ./spec/rspec/core/drb_command_line_spec.rb:39
RSpec::Core::Runner#run with --drb or -X and a DRb server is running builds a DRbCommandLine and runs the specs
0.0744 seconds ./spec/rspec/core/runner_spec.rb:47
command line when a custom order is configured orders the groups and examples by the provided strategy
0.06924 seconds ./spec/command_line/order_spec.rb:169
RSpec::Core::ConfigurationOptions#configure sends pattern before files_or_directories_to_run
0.06649 seconds ./spec/rspec/core/configuration_options_spec.rb:48
Top 5 slowest example groups:
RSpec::Core::Formatters::HtmlFormatter
0.05861 seconds average (0.05861 seconds / 1 example) ./spec/rspec/core/formatters/html_formatter_spec.rb:9
RSpec::Core::Formatters::TextMateFormatter
0.05713 seconds average (0.1714 seconds / 3 examples) ./spec/rspec/core/formatters/text_mate_formatter_spec.rb:9
command line
0.05218 seconds average (0.31307 seconds / 6 examples) ./spec/command_line/order_spec.rb:3
::DRbCommandLine
0.02016 seconds average (0.16127 seconds / 8 examples) ./spec/rspec/core/drb_command_line_spec.rb:4
RSpec::Core::Runner
0.01822 seconds average (0.10931 seconds / 6 examples) ./spec/rspec/core/runner_spec.rb:5
Core: New --warnings flag to enable Ruby’s warning mode
You can now pass the --warnings or -w flag to enable ruby’s warning
mode.
Core: Shared example groups are scoped to the context they are defined in
Before 2.14, shared example groups were stored in a global hash, could be defined in any context, and could be used from any context. In 2.14, this has changed: shared example groups are now scoped to the context they are defined in. That means you can now do this:
describe MySinatraApp1 do
shared_examples_for "error handling" do
# some examples would go here
end
context 'GET to /foo' do
include_examples "error handling"
end
context 'GET to /bar' do
include_examples "error handling"
end
end
describe MySinatraApp2 do
shared_examples_for "error handling" do
# some different examples would go here
end
context 'GET to /foo' do
include_examples "error handling"
end
context 'GET to /bar' do
include_examples "error handling"
end
end
Here there are two different "error handling" shared example
groups, each scoped to (and used from) a different example group.
As demonstrated here, shared example groups are available from
the context they are defined in or from any nested context.
In 2.14, shared example groups declared in sibling contexts
are still available to maintain backwards compatibility,
but will print a deprecation warning. In 3.0, you will not
be able to use a shared example group that was defined in
a sibling context.
Core: Deprecation output now configurable
RSpec 2.14 has deprecated a number of things in preparation for removal in 3.0. To help reduce the noisiness of the increased number of deprecations, there’s a new option that can direct deprecation warnings to a file:
# spec_helper.rb
RSpec.configure do |rspec|
rspec.deprecation_stream = 'log/deprecations.log'
# or
rspec.deprecation_stream = File.open("/path/to/file", "w")
end
Normally, deprecation warnings get printed to stderr. When
you configure this, it’ll send deprecation warnings to the
configured file instead, and at the end of the spec run
it will print out a message like:
2 deprecations logged to log/deprecations.log
Mocks: New message expectation syntax
In RSpec 2.11, we added a new syntax to rspec-expectations that removes a reliance on monkey-patching, avoiding certain kinds of problems related to proxy objects. In RSpec 2.14, we’ve extended that same syntax to rspec-mocks:
mailer = double("Mailer")
# old syntax:
mailer.stub(:deliver_welcome_email)
mailer.should_receive(:deliver_welcome_email).with(an_instance_of(User))
# new syntax
allow(mailer).to receive(:deliver_welcome_email)
expect(mailer).to receive(:deliver_welcome_email).with(an_instance_of(User))
For more details, read Sam Phippen’s announcement blog post from the 2.14.0.rc1 release.
Mocks: Spies
Joe Ferris from Thoughtbot implemented this new feature. Traditionally, rspec-mocks has required that you set a message expectation before the message is received:
mailer = double("Mailer")
expect(mailer).to receive(:deliver_welcome_email).with(an_instance_of(User))
UserCreationService.new(mailer).create_user(params)
In some situations, this ordering feels backwards (particularly if you try to organize your tests using an arrange/act/assert pattern). Spies allow you to assert that a message was received after the fact:
mailer = double("Mailer", deliver_welcome_email: nil)
UserCreationService.new(mailer).create_user(params)
expect(mailer).to have_received(:deliver_welcome_email).with(an_instance_of(User))
Note that you first have to stub the message you will later expect
so that rspec-mocks can spy on it. (There’s no feasible performant
way for rspec-mocks to automatically spy on all method calls).
Alternately, you can create your test double as a null object,
(using double().as_null_object) which has the effect of
auto-spying on all messages sent to that object:
mailer = double("Mailer").as_null_object
UserCreationService.new(mailer).create_user(params)
expect(mailer).to have_received(:deliver_welcome_email).with(an_instance_of(User))
Docs
RDoc
- http://rubydoc.info/gems/rspec-core
- http://rubydoc.info/gems/rspec-expectations
- http://rubydoc.info/gems/rspec-mocks
- http://rubydoc.info/gems/rspec-rails
Cucumber Features
- http://relishapp.com/rspec/rspec-core
- http://relishapp.com/rspec/rspec-expectations
- http://relishapp.com/rspec/rspec-mocks
- http://relishapp.com/rspec/rspec-rails
Release Notes
rspec-core 2.14.0
Enhancements:
- Improved Windows detection inside Git Bash, for better
--colorhandling. - Add profiling of the slowest example groups to
--profileoption. The output is sorted by the slowest average example groups. - Don’t show slow examples if there’s a failure and both
--fail-fastand--profileoptions are used (Paweł Gościcki). - Rather than always adding
specto the load path, add the configured--default-pathto the load path (which defaults tospec). This better supports folks who choose to put their specs in a different directory (John Feminella). - Add some logic to test time duration precision. Make it a function of time, dropping precision as the time increases. (Aaron Kromer)
- Add new
backtrace_inclusion_patternsconfig option. Backtrace lines that match one of these patterns will always be included in the backtrace, even if they match an exclusion pattern, too (Sam Phippen). - Support ERB trim mode using the
-when parsing.rspecas ERB (Gabor Garami). - Give a better error message when let and subject are called without a block. (Sam Phippen).
- List the precedence of
.rspec-localin the configuration documentation (Sam Phippen) - Support
{a,b}shell expansion syntax in--patternoption (Konstantin Haase). - Add cucumber documentation for –require command line option (Bradley Schaefer)
- Expose configruation options via config:
config.libsreturns the libs configured to be added onto the load pathfull_backtrace?returns the state of the backtrace cleanerdebug?returns true when the debugger is loadedline_numbersreturns the line numbers we are filtering by (if any)full_descriptionreturns the RegExp used to filter descriptions (Jon Rowe)
- Add setters for RSpec.world and RSpec.configuration (Alex Soulim)
- Configure ruby’s warning behaviour with
--warnings(Jon Rowe) - Fix an obscure issue on old versions of
1.8.7whereTime.dupwouldn’t allow access toTime.now(Jon Rowe) - Make
shared_examples_forcontext aware, so that keys may be safely reused in multiple contexts without colliding. (Jon Rowe) - Add a configurable
deprecation_stream(Jon Rowe) - Publish deprecations through a formatter (David Chelimsky)
- Apply focus to examples defined with
fit(equivalent ofit "description", focus: true) (Michael de Silva)
Bug fixes:
- Make JSON formatter behave the same when it comes to
--profileas the text formatter (Paweł Gościcki). - Fix named subjects so that if an inner group defines a method that
overrides the named method,
subjectstill retains the originally declared value (Myron Marston). - Fix random ordering so that it does not cause
randin examples in nested sibling contexts to return the same value (Max Shytikov). - Use the new
backtrace_inclusion_patternsconfig option to ensure that folks who develop code in a directory matching one of the default exclusion patterns (e.g.gems) still get the normal backtrace filtering (Sam Phippen). - Fix ordering of
beforehooks so thatbeforehooks declared inRSpec.configurerun beforebeforehooks declared in a shared context (Michi Huber and Tejas Dinkar). - Fix
Example#full_descriptionso that it gets filled in by the last matcher description (asExample#descriptionalready did) when no doc string has been provided (David Chelimsky). - Fix the memoized methods (
letandsubject) leakingdefine_methodas apublicmethod. (Thomas Holmes and Jon Rowe) (#873) - Fix warnings coming from the test suite. (Pete Higgins)
- Ensure methods defined by
lettake precedence over others when there is a name collision (e.g. from an included module). (Jon Rowe, Andy Lindeman and Myron Marston)
Deprecations
- Deprecate
Configuration#backtrace_clean_patternsin favor ofConfiguration#backtrace_exclusion_patternsfor greater consistency and symmetry with newbacktrace_inclusion_patternsconfig option (Sam Phippen). - Deprecate
Configuration#requires=in favor of using ruby’srequire. Requires specified by the command line can still be accessed by theConfiguration#requirereader. (Bradley Schaefer) - Deprecate calling
SharedExampleGroupsdefined across sibling contexts (Jon Rowe)
rspec-expectations 2.14.0
Enhancements:
- Enhance
yield_controlso that you can specify an exact or relative number of times:expect { }.to yield_control.exactly(3).times,expect { }.to yield_control.at_least(2).times, etc (Bartek Borkowski). - Make the differ that is used when an expectation fails better handle arrays by splitting each element of the array onto its own line. (Sam Phippen)
- Accept duck-typed strings that respond to
:to_stras expectation messages. (Toby Ovod-Everett)
Bug fixes:
- Fix differ to not raise errors when dealing with differently-encoded strings (Jon Rowe).
- Fix
expect(something).to be_within(x).percent_of(y)where x and y are both integers (Sam Phippen). - Fix
havematcher to handle the fact that on ruby 2.0,Enumerator#sizemay return nil (Kenta Murata). - Fix
expect { raise s }.to raise_error(s)where s is an error instance on ruby 2.0 (Sam Phippen). - Fix
expect(object).to raise_errorpassing. This now warns the user and fails the spec (tomykaira). - Values that are not matchers use
#inspect, rather than#descriptionfor documentation output (Andy Lindeman, Sam Phippen). - Make
expect(a).to be_within(x).percent_of(y)work with negative y (Katsuhiko Nishimra). - Make the
be_predicatematcher work as expected used withexpect{...}.to change...(Sam Phippen).
Deprecations
- Deprecate
expect { }.not_to raise_error(SpecificErrorClass)orexpect { }.not_to raise_error("some specific message"). Using these was prone to hiding failures as they would allow any other error to pass. (Sam Phippen and David Chelimsky)
rspec-mocks 2.14.0
Enhancements:
- Refactor internals so that the mock proxy methods and state are held
outside of the mocked object rather than inside it. This paves the way
for future syntax enhancements and removes the need for some hacky
work arounds for
any_instancedup'ing andYAMLserialization, among other things. Note that the code now relies upon__id__returning a unique, consistent value for any object you want to mock or stub (Myron Marston). - Add support for test spies. This allows you to verify a message
was received afterwards using the
have_receivedmatcher. Note that you must first stub the method or use a null double. (Joe Ferris and Joël Quenneville) - Make
at_leastandat_moststyle receive expectations print that they were expecting at least or at most some number of calls, rather than just the number of calls given in the expectation (Sam Phippen) - Make
withstyle receive expectations print the args they were expecting, and the args that they got (Sam Phippen) - Fix some warnings seen under ruby 2.0.0p0 (Sam Phippen).
- Add a new
:expectsyntax for message expectations (Myron Marston and Sam Phippen). - Document test spies in the readme. (Adarsh Pandit)
- Add an
array_includingmatcher. (Sam Phippen) - Add a syntax-agnostic API for mocking or stubbing a method. This is intended for use by libraries such as rspec-rails that need to mock or stub a method, and work regardless of the syntax the user has configured (Paul Annesley, Myron Marston and Sam Phippen).
Bug Fixes:
- Fix
any_instanceso that a frozen object can bedup‘d when methods have been stubbed on that type usingany_instance(Jon Rowe). - Fix
and_call_originalso that it properly raises anArgumentErrorwhen the wrong number of args are passed (Jon Rowe). - Fix
doubleon 1.9.2 so you can wrap them in an Array usingArray(my_double)(Jon Rowe). - Fix
stub_constandhide_constto handle constants that redefinesend(Sam Phippen). - Fix
Marshal.dumpextension so that it correctly handles nil. (Luke Imhoff, Jon Rowe) - Fix isolation of
allow_message_expectations_on_nil(Jon Rowe) - Use inspect to format actual arguments on expectations in failure messages (#280, Ben Langfeld)
- Protect against improperly initialised test doubles (#293) (Joseph Shraibman and Jon Rowe)
- Fix
doubleso that it sets up passed stubs correctly regardless of the configured syntax (Paul Annesley). - Allow a block implementation to be used in combination with
and_yield,and_raise,and_returnorand_throw. This got fixed in 2.13.1 but failed to get merged into master for the 2.14.0.rc1 release (Myron Marston). Marshal.dumpdoes not unnecessarily duplicate objects when rspec-mocks has not been fully initialized. This could cause errors when usingsporkor similar preloading gems (Andy Lindeman).
Deprecations:
- Deprecate
stubandmockas aliases fordouble.doubleis the best term for creating a test double, and it reduces confusion to have only one term (Michi Huber). - Deprecate
stub!andunstub!in favor ofstubandunstub(Jon Rowe). - Deprecate
at_least(0).timesandany_number_of_times(Michi Huber).
rspec-rails 2.14.0
Enhancements:
- Preliminarily support Rails 4.1 by updating adapters to support Minitest 5.0. (Andy Lindeman)
Bug fixes:
- Rake tasks do not define methods that might interact with other libraries. (Fujimura Daisuke)
- Reverts fix for out-of-order
letdefinitions in controller specs after the issue was fixed upstream in rspec-core. (Andy Lindeman) - Fixes deprecation warning when using
expect(Model).to have(n).recordswith Rails 4. (Andy Lindeman) rake statsruns correctly when spec files exist at the top level of the spec/ directory. (Benjamin Fleischer)