Minitest Quick Reference
UPDATE: I’ve added a new section on stubbing with MiniTest and a few helpful comments to the code samples.
MiniTest, as the name suggests, is a small and fast unit testing framework. Shipped with Ruby 1.9, MiniTest supports a complete suite of testing capabilities such as TDD, BDD, mocking, and benchmarking.
This quick reference aims to demonstrate MiniTest’s main concepts and provide real world examples to get you acquainted quickly. Let’s start with MiniTest::Spec.
MiniTest::Spec
Provides RSpec-like matchers and contexts right out of the box.
require 'minitest/autorun'
describe Hipster, "Demonstration of MiniTest" do
# Runs codes before each expectation
before do
@hipster = Hipster.new
end
# Runs code after each expectation
after do
@hipster.destroy!
end
# Define accessors - lazily runs code when it's first used
let(:hipster) { Hipster.new}
let(:traits) { ["silly hats", "skinny jeans"] }
let(:labels) { Array.new }
# Even lazier accessor - assigns `subject` as the name for us
# this equivalent to let(:subject) { Hipster.new }
subject { Hipster.new }
it "#define" do
hipster.define.must_equal "you wouldn't understand"
end
it "#walk?" do
skip "I prefer to skip"
end
describe "when asked about the font" do
it "should be helvetica" do
@hipster.preferred_font.must_equal "helvetica"
end
end
describe "when asked about mainstream" do
it "won't be mainstream" do
@hipster.mainstream?.wont_equal true
end
end
end
Matchers (must | wont)
In most cases you can switch between must
for positive expectations and wont
for negative expectations.
Assertion | Examples |
---|---|
must_be |
labels.size.must_be :==, 0 |
must_be_close_to |
traits.size.must_be_close_to 1,1 |
must_be_empty |
labels.must_be_empty |
must_be_instance_of |
hipster.must_be_instance_of Hipster |
must_be_kind_of |
labels.must_be_kind_of Enumerable |
must_be_nil |
labels.first.must_be_nil |
must_be_same_as |
traits.must_be_same_as traits |
must_be_silent |
proc { "no stdout or stderr" }.must_be_silent |
must_be_within_epsilon |
traits.size.must_be_within_epsilon 1,1 |
must_equal |
traits.size.must_equal 2 |
must_include |
traits.must_include "skinny jeans" |
must_match |
traits.first.must_match /silly/ |
must_output |
proc { print "#{traits.size}!" }.must_output "2!" |
must_respond_to |
traits.must_respond_to :count |
must_raise |
proc { traits.foo }.must_raise NoMethodError |
must_send |
traits.must_send [traits, :values_at, 0] |
must_throw |
proc { throw Exception if traits.any? }.must_throw Exception |
MiniTest::Unit::TestCase
Provides a rich set of assertions to make your tests clean and readable.
require 'minitest/autorun'
class TestHipster < MiniTest::Unit::TestCase
def setup
@hipster = Hipster.new
@labels = Array.new
@traits = ["silly hats", "skinny jeans"]
end
def teardown
@hipster.destroy!
end
def test_for_helvetica_font
assert_equal "helvetica!", @hipster.preferred_font
end
def test_not_mainstream
refute @hipster.mainstream?
end
end
Assertions (assert | refute)
Toggle between assert
for positive assertions and refute
for negative assertions.
Assertion | Example |
---|---|
assert |
assert @traits.any?, "empty subjects" |
assert_empty |
assert_empty @labels |
assert_equal |
assert_equal 2, @traits.size |
assert_in_delta |
assert_in_delta @traits.size, 1,1 |
assert_in_epsilon |
assert_in_epsilon @traits.size, 1, 1 |
assert_includes |
assert_includes @traits, "skinny jeans" |
assert_instance_of |
assert_instance_of Hipster, @hipster |
assert_kind_of |
assert_kind_of Enumerable, @labels |
assert_match |
assert_match @traits.first, /silly/ |
assert_nil |
assert_nil @labels.first |
assert_operator |
assert_operator @labels.size, :== , 0 |
assert_output |
assert_output("Size: 2") { print "Size: #{@traits.size}"} |
assert_raises |
assert_raises(NoMethodError) { @traits.foo } |
assert_respond_to |
assert_respond_to @traits, :count |
assert_same |
assert_same @traits, @traits, "It's the same object silly" |
assert_send |
assert_send [@traits, :values_at, 0] |
assert_silent |
assert_silent { "no stdout or stderr" } |
assert_throws |
assert_throws(Exception,'is empty') {throw Exception if @traits.any?} |
MiniTest#stub
Minitest provides a simple stub
method we can use to return a pre-determined value.
require 'minitest/autorun'
describe Hipster, "Demonstrates stubbing with Minitest" do
let(:hipster) { Hipster.new }
it "trendy if time is now" do
assert hipster.trendy? DateTime.now
end
it "it is NOT trendy if 2 weeks has past" do
DateTime.stub :now, (Date.today.to_date - 14) do
refute hipster.trendy? DateTime.now
end
end
end
MiniTest::Mock
A simple and clean mock system. There two essential methods at our disposal:
expect
and verify
.
require 'minitest/autorun'
# Make all of our Twitter updates hip
class Twipster
def initialize(twitter)
@twitter = twitter # A Twitter API client
end
def tweet(message)
@twitter.update("#{message} #lolhipster")
end
end
# Uses Mock#expect and Mock#verify
describe Twipster, "Make every tweet a hipster tweet." do
before do
@twitter = MiniTest::Mock.new # Mock our Twitter API client
end
let(:twipster) { Twipster.new(@twitter) }
let(:message) { "Skyrim? Too mainstream."}
it "should append a #lolhipster hashtag and update Twitter with our status" do
@twitter.expect :update, true, ["#{message} #lolhipster"]
@twipster.tweet(message)
assert @twitter.verify # verifies tweet and hashtag was passed to `@twitter.update`
end
end
Resources
- MiniTest on Github
- MiniTest Rdoc
- Using MiniTest::Spec with Rails
- Ruby Inside: A MiniTest::Spec Tutorial: Elegant Spec-Style Testing That Comes With Ruby
I hope you found this quick guide valuable. Please let me know if you’d like to see anything else included and feel free to ask questions or give feedback in the comments section.