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

  1. MiniTest on Github
  2. MiniTest Rdoc
  3. Using MiniTest::Spec with Rails
  4. 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.