Minitest and Rspec

Minitest and Rspec

I'm one of the RSpec developers, and have never used minitest, so take my biases into account when reading this answer.

By and large, RSpec's power comes from the fact that it reifies so many testing concepts into first class objects. Where Test::Unit and Minitest use simple methods for making assertions, RSpec uses first-class matcher objects that support negation, self-description and more. RSpec's examples are first-class objects that support rich metadata; minitest/spec compiles it blocks down into simple methods, which don't support the same sort of rich metadata. RSpec supports specifying shared behaviors using a first-class construct (shared example groups) that accepts arguments; w/ minitest you can use inheritance or a mixin to re-use tests, but it doesn't have the same sort of first-class support. RSpec has an explicit formatter API (and there are many third party formatters that use it); I'm not aware of minitest having the same sort of first-class formatter API.

As somebody who is constantly running tests and practicing TDD all day long, I find the power RSpec gives me to be very useful. Many people find it to be overkill, though, and there is an added cognitive cost to the extra abstractions.

Here are some specific features RSpec has that I believe minitest lacks:

  • before(:all) hooks (note this is a power user feature of RSpec that should rarely be used; I've only used it on a few occasions in many years of using RSpec)
  • around(:each) hooks
  • Shared example groups
  • Shared contexts
  • Rich metadata support that can be used to control which examples get run, which example groups shared contexts get included in, which example groups modules get mixed into and more.
  • Integrated support for a wide range of mocking features w/ rspec-mocks; Minitest::Mock is far simpler and more limited in comparison.
  • RSpec has rspec-fire, which is awesome.

Benefits of using Minitest:

  • It's built into the standard library so you don't need to install anything extra.
  • It can either be used in def test_blah or it 'blah' styles.
  • The code base is very small and simple. RSpec, by virtue of it's older age and additional features, is larger in comparison.
  • Minitest loads faster than RSpec (it's about 4 files of code compared to RSpec having many files spread across 3 gems)--but note that RSpec is by no means slow; in most of my projects these days, I get test feedback from RSpec in under a second (and often in under 500 ms).

Overall, it's a bit like Sinatra vs. Rails, and I think Minitest and RSpec are both fine choices depending on your needs.

One last thing: if there are specific aspects of Minitest you like better, but other things you like better about RSpec, they can easily be mixed and matched. I wrote a blog post about this, if you're interested.

Rails 4: using MiniTest AND Rspec

I just revisited this and it seems like Rspec and Minitest work fine together "out of the box" without needing minitest-rails.

I'm not however using minitest/spec so I don't know about how that would integrate.

My issue was that the project in question was explicitly setting up individual railties in config/application.rb just to exclude "rails/test_unit/railtie" which is great if you just want rspec.

I put it back to the default

require 'rails/all'

and now both rspec specs run with

rake spec

and minitest tests run with

rake test

I wanted both to run buy default with just

rake

So I put this in my Rakefile

Rake::Task["default"].clear if Rake::Task.task_defined?("default")
task :default do
puts "Starting specs"
system('bundle exec rake spec')

puts "Starting Minitest tests"
system('bundle exec rake test')
end

Rspec method similar to MiniTest 'assert'

Rspec uses expect() in a similar way to Minitest's assert. expect(actual).to eq(expected) You can get in depth with the docs at https://www.relishapp.com/rspec/ . Note that there are few different ways to test the truth in Rspec(from https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers):

expect($b.link(:text => 'DAM').present?).to be true      # passes if actual == true
expect($b.link(:text => 'DAM').present?).to eq true # passes if actual == true
expect($b.link(:text => 'DAM').present?).to be_truthy # passes if actual is truthy (not nil or false)

If you spend a lot of time in rspec, you can also create custom matchers for common tests that extend the use of "be" e.g.

RSpec::Matchers.define :be_present do
match do |actual|
actual.present?
end
end

expect($b.link(:text => 'DAM')).to be_present # passes if $b.link(:text => 'DAM').present? == true


Related Topics



Leave a reply



Submit