![Screenshot 2014-06-15 10.38.59](https://uploads.sitepoint.com/wp-content/uploads/2014/06/1402843162Screenshot-2014-06-15-10.38.59-300x142.png)
Back before RSpec and Cucumber, a core library in Ruby called Test Unit existed. It was simply a framework for unit testing code. Ever since Ruby 1.9.3, however, Test Unit has been replaced by Minitest as the included testing framework for Ruby. In this article, we’re going to overview Minitest (as it has now superceded Test Unit) and the benefits of shoulda-context, a Test::Unit
/Minitest
framework.
Prerequisites
- Ruby (duh; current 2.1.2 would be best)
- The ability to run
gem install GEM
without a hassle. - A small amount of TDD knowledge, with a sprinkle of BDD.
Test driven development (TDD) has always been a fixture in the Ruby community. It is a core concept in extreme programming and is used in virtually every Ruby project. Making unit tests with Minitest is simple, but first, we need a Ruby library to test. Our final project structure will look like this:
.
├── Gemfile
├── Gemfile.lock
├── Rakefile
├── lib
│ └── calculator.rb
└── test
├── test_calculator.rb
├── test_calculator_basic.rb
└── test_helper.rb
You can find the repo for this project here.
Our library is a calculator with two methods: add
and subtract
.
class Calculator
def add(num1, num2)
num1 + num2
end
def subtract(num1, num2)
num1 - num2
end
end
To test this library with Minitest, create a test class that inherits from Minitest::Test
.
# file: test/test_calculator_basic.rb
require 'minitest/autorun'
require 'calculator' # don't worry, this works
class TestCalculator < Minitest::Test
end
Tests inside of this class are methods that start with test_
and should describe what the test is testing.
# file: test/test_calculator_basic.rb
require 'minitest/autorun'
require 'calculator'
class TestCalculator < Minitest::Test
def setup
@calc = Calculator.new
end
def test_proper_addition
assert_equal 4, @calc.add(2, 2)
end
def test_proper_subtraction
assert_equal 0, @calc.subtract(2, 2)
end
end
To run this test, use the following command: $ ruby -I test:lib test/test_calculator_basic.rb
. This may seem a little repetetive, especially if you plan on using a CI server, so we can use a simple Rake task for automation.
# file: Rakefile
require 'rake/testtask'
Rake::TestTask.new do |task|
task.libs << %w(test lib)
task.pattern = 'test/test_*.rb'
end
task :default => :test
Now, the tests run by simply calling rake
or rake test
. That should give us the following output:
Run options: --seed 41508
# Running:
..
Finished in 0.001047s, 1910.2197 runs/s, 1910.2197 assertions/s.
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
As you can see, our tests passed. Let’s add some more…
# file: lib/test_calculator_basic.rb
require 'minitest/autorun'
require 'calculator'
class TestCalculator < Minitest::Test
def setup
@calc = Calculator.new
end
# add
def test_add
assert_equal 4, @calc.add(2, 2)
end
def test_failing_add
refute_equal 5, @calc.add(2, 2)
end
# subtract
def test_subtract
assert_equal 0, @calc.subtract(2, 2)
end
def test_failing_subtract
refute_equal -1, @calc.subtract(2, 2)
end
end
The results of this are similar to the last ones.
Run options: --seed 4571
# Running:
....
Finished in 0.001081s, 3700.2775 runs/s, 3700.2775 assertions/s.
4 runs, 4 assertions, 0 failures, 0 errors, 0 skips
You may have noticed that the test methods are starting to get more confusing to read. This is because you’re limited by_underscored_names_as_tests
. This is where shoulda-context comes in. The good folks over at thoughtbot created this library to help give context to unit tests. Here is the above test written in shoulda-context format:
# file: lib/test_calculator.rb
require 'minitest/autorun'
require 'shoulda/context'
require 'calculator'
class TestCalculator < Minitest::Test
context 'a calculator' do
setup do # notice the difference
@calc = Calculator.new
end
should 'add two numbers properly' do
assert_equal 4, @calc.add(2, 2)
end
should 'not add incorrectly' do
refute_equal 5, @calc.add(2, 2)
end
should 'subtract two numbers properly' do
assert_equal 0, @calc.subtract(2, 2)
end
should 'not subtract incorrectly' do
refute_equal -1, @calc.subtract(2, 2)
end
end
end
If you haven’t yet, run gem install shoulda-context
in your terminal to install shoulda-context.
As you can see, the tests are much more readable. A human can read the tests like this: context: should 'do something'
. For example, the first test can be read as: a calculator should add two numbers properly
. This is much more expressive than the previous example. The tests now seem more Ruby-esque.
Expanding: Output
If you’ve been following along with the code examples, then you may notice that the test output isn’t as nice as RSpec or Cucumber’s output. To fix this, we can use a little gem called minitest-reporters.
First, we’re going to split up our tests a little more. If you have experience with Rails and testing, then you have probably used test_helper.rb
. We can do the same thing in our project by just creating a file in our tests directory called test_helper.rb
Inside of test_helper.rb
, we’re going to put the first two beginning require
statements that we have been using in our tests.
# file: test/test_helper.rb
require 'minitest/autorun'
require 'shoulda/context'
Notice that we did not include require 'calculator'
. This is done because we could expand our library at some point beyond just the Calculator
class. Since not everything that we test in our library will need to include calculator
, we do not include it in test_helper.rb
.
Our calculator tests file should now look something like this:
# file: test/test_calculator.rb
require 'test_helper'
require 'calculator'
# ... lots of tests ...
To setup minitest-reporters with our new setup, first install the gem (gem install minitest-reporters
). Now, open up test_helper.rb
again and add the following:
# file: test/test_helper.rb
require 'minitest/autorun'
require 'minitest/reporters' # requires the gem
require 'shoulda/context'
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new # spec-like progress
If we run the tests (ruby -I test:lib test/test_calculator.rb
or rake test
with only one testing file), we should see:
Started
TestCalculator
test: a calculator should subtract two numbers properly. PASS (0.00s)
test: a calculator should not add incorrectly. PASS (0.00s)
test: a calculator should add two numbers properly. PASS (0.00s)
test: a calculator should not subtract incorrectly. PASS (0.00s)
Finished in 0.00141s
4 tests, 4 assertions, 0 failures, 0 errors, 0 skips
Much more readable and it has color! Notice how the format is the same as how the tests read to a human. This is how it should be.
Conclusion
Testing is not only recommended, but it is almost required when working on a Ruby project. Tools like shoulda-context are here to help ease that process. We covered Minitest basics, automated testing, shoulda-context, and fancy (colored, human-readable) output. If you’d like to learn more, check out these links:
- Minitest Library (included with Ruby)
- Minitest Repo (official repository)
- shoulda-context (shoulda-context GitHub page)
- minitest-reporters (minitest-reporters GitHub page)
- Code from This Article (all of the code from this article)
- Extreme Programming – Wikipedia (XP wikipedia page)
- Extreme Programming – Official (XP official website)
- DDH Offended by RSpec (old, but still relevant)
Frequently Asked Questions (FAQs) about Minitest and Shoulda
What are the key differences between Minitest and other testing frameworks?
Minitest is a lightweight, fast, and clean testing framework for Ruby. It provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking. Unlike other testing frameworks like RSpec, Minitest is simpler and has less syntax, making it easier to read and write tests. It’s also part of the Ruby standard library, so you don’t need to install any additional gems to use it.
How do I get started with Minitest?
To get started with Minitest, you need to require ‘minitest/autorun’ at the top of your test file. Then, create a class that inherits from Minitest::Test and define your test methods. Each test method should start with ‘test_’. To make an assertion, you can use the assert method, which takes a boolean and fails if the boolean is false.
How can I use Shoulda with Minitest?
Shoulda is a testing library that works with Minitest and provides additional matchers to make your tests more expressive and readable. To use Shoulda with Minitest, you need to add the shoulda-context and shoulda-matchers gems to your Gemfile and bundle install. Then, require ‘shoulda/context’ and ‘shoulda/matchers’ in your test file.
What are some common assertions in Minitest?
Minitest provides a variety of assertions to test your code. Some common ones include assert, which checks if a value is truthy, refute, which checks if a value is falsy, assert_equal, which checks if two values are equal, and assert_raises, which checks if a block of code raises a certain exception.
How can I run a specific test in Minitest?
To run a specific test in Minitest, you can use the -n or –name option followed by the test name when running your test file. For example, if you have a test named test_example, you can run it with ruby -Ilib:test your_test_file.rb -n test_example.
How can I use mocks and stubs in Minitest?
Minitest provides built-in support for mocks and stubs. A mock is an object that simulates the behavior of a real object in a controlled way, while a stub is a method that simulates the behavior of a real method. To create a mock, you can use Minitest::Mock.new. To create a stub, you can use the stub method, which takes a method name and a return value.
How can I write BDD-style tests with Minitest and Shoulda?
Shoulda allows you to write BDD-style tests with Minitest. Instead of defining test methods, you can define a context and specify what should happen in that context. For example, you can write context ‘when the user is logged in’ do; should ‘display the user’s name’ do; …; end; end.
How can I test performance with Minitest?
Minitest includes a benchmarking module that allows you to test the performance of your code. To use it, you need to require ‘minitest/benchmark’ and create a class that inherits from Minitest::Benchmark. Then, you can define your benchmark methods, which should start with ‘bench_’.
How can I customize the output of Minitest?
Minitest allows you to customize its output by creating a custom reporter. A reporter is an object that responds to certain methods like record, report, and start. To use a custom reporter, you need to add it to Minitest.reporter.reporters.
How can I integrate Minitest with Rails?
Minitest is the default testing framework in Rails. When you create a new Rails application, it automatically generates a test directory with a helper file that requires ‘minitest/rails’. You can write your tests in the test/models, test/controllers, and test/integration directories. To run your tests, you can use the rails test command.
![Jesse Herrick](https://uploads.sitepoint.com/wp-content/uploads/2015/06/1433174717Profile-2015-May-96x96.jpg)
Jesse Herrick is an avid Ruby developer who specializes in web development. He is a back-end developer at Littlelines and loves programming. You can read his personal blog at: https://jesse.codes.