Ruby MiniTest ๐Ÿ”ฌ- Minimal replacement for test-unit

Minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking.

minitest/test is a small and incredibly fast unit testing framework. It provides a rich set of assertions to make your tests clean and readable.

minitest/spec is a functionally complete spec engine. It hooks onto minitest/test and seamlessly bridges test assertions over to spec expectations.

minitest/benchmark is an awesome way to assert the performance of your algorithms in a repeatable manner. Now you can assert that your newb co-worker doesn’t replace your linear algorithm with an exponential one!

minitest/mock by Steven Baker, is a beautifully tiny mock (and stub) object framework.

minitest/pride shows pride in testing and adds coloring to your test output

minitest/test_task – a full-featured and clean rake task generator.
– Minitest Github

โ™ฆ๏ธ Incredibly small and fast runner, but no bells and whistles.

Let’s take the given example in the doc, we’d like to test the following class:

class Meme
  def i_can_has_cheezburger?
    "OHAI!"
  end

  def will_it_blend?
    "YES!"
  end
end

๐Ÿงช Unit tests

Define your tests as methods beginning with test_.

require "minitest/autorun"

class TestMeme < Minitest::Test
  def setup
    @meme = Meme.new
  end

  def test_that_kitty_can_eat
    assert_equal "OHAI!", @meme.i_can_has_cheezburger?
  end

  def test_that_it_will_not_blend
    refute_match /^no/i, @meme.will_it_blend?
  end

  def test_that_will_be_skipped
    skip "test this later"
  end
end

setup ()

# File lib/minitest/test.rb, line 153
def setup; end

โ™ฆ๏ธ Runs before every test. Use this to set up before each test run.

The terms “unit test” and “spec” are often used in software testing, and while they can overlap, they have some key differences:

๐Ÿงช Unit Test vs ๐Ÿ“‹ Spec: Key Differences

๐Ÿ”ฌUnit Test

  • Purpose: Tests a single unit of code (typically a method, function, or class) in isolation
  • Scope: Very focused and narrow – tests one specific piece of functionality
  • Style: Usually follows a more traditional testing approach with setup, execution, and assertion
  • Framework examples: Minitest (like in your Ruby file), JUnit, pytest
  • Structure: Often uses test_ prefix or Test classes with assertion methods

๐Ÿ“ Spec (Specification)

  • Purpose: Describes the behavior and requirements of the system in a more readable, documentation-like format
  • Scope: Can cover unit-level, integration, or acceptance testing
  • Style: Uses natural language descriptions that read like specifications
  • Framework examples: RSpec, Jasmine, Mocha, Jest
  • Structure: Uses descriptive blocks like describe, it, should

โš–๏ธ Key Differences

1. โœ๏ธ Writing Style:

  • Unit Test
    def test_array_is_empty with assertions
  • Spec
    describe "when array is empty" do
    it "should return error message"

2. ๐Ÿ‘๏ธ Readability:

  • Unit Test: More code-focused, technical
  • Spec: More human-readable, business-focused

3. ๐ŸŽฏ Philosophy:

  • Unit Test: Test the implementation
  • Spec: Specify the behavior (BDD – Behavior Driven Development)

๐Ÿ“Š Example Comparison

๐Ÿท๏ธ Our current Minitest code:

def array_is_an_empty_array
  assert_equal 'Provide an array with length 2 or more', two_sum([], 9)
end

๐ŸŽจ RSpec equivalent (spec style):

describe "two_sum" do
  context "when array is empty" do
    it "returns an error message" do
      expect(two_sum([], 9)).to eq('Provide an array with length 2 or more')
    end
  end
end

Both test the same functionality, but specs emphasize describing behavior in natural language, making them easier for non-technical stakeholders to understand. ๐ŸŽ‰

๐Ÿ”ฌ Mini-test equivalent:

# frozen_string_literal: true

require 'minitest/spec'
require_relative 'two_sum'

describe "TwoSum" do
  describe "when array is empty" do
    it "returns an error message" do
      _(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
    end
  end
end

The underscore _() in Minitest spec style is a wrapper method that converts the value into an expectation object.

Here’s why it’s used:

๐Ÿ” Why the Underscore _()?
๐ŸŽฏ Purpose:

The _() method wraps your actual value and returns a special expectation object that has assertion methods like must_equal, must_be, etc.

โš™๏ธ How it works:
# This:
_(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'

# Is equivalent to:
# 1. two_sum([], 9) returns some value
# 2. _() wraps that value into an expectation object
# 3. .must_equal() is called on that expectation object
๐Ÿ”„ Alternative Syntaxes
1. ๐Ÿ“ Using expect() (more readable):
expect(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
2. ๐Ÿ”ง Using value() (explicit):
value(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
3. ๐Ÿท๏ธ Traditional unit test style (no wrapper needed):
assert_equal 'Provide an array with length 2 or more', two_sum([], 9)
๐Ÿ’ก Why underscore specifically?
  • Minimal syntax: _() is short and doesn’t clutter the code
  • Ruby convention: Underscore often indicates “throwaway” or “utility” variables
  • Non-conflicting: Unlikely to conflict with your method names
  • Chainable: Creates a fluent interface for assertions
๐ŸŽจ Complete comparison:
# Spec style with underscore
_(result).must_equal expected

# Spec style with expect (more readable)
expect(result).must_equal expected

# Unit test style (no wrapper)
assert_equal expected, result

The expect() version is often preferred because it’s more self-documenting!

๐ŸŽจ Alternative Spec Style with Expectation Syntax:

# frozen_string_literal: true

require 'minitest/spec'
require_relative 'two_sum'

describe "TwoSum" do
  describe "when array is empty" do
    it "returns an error message" do
      expect(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
    end
  end
end

โš–๏ธ Key Differences in Minitest

๐Ÿ”ง Setup Required:
  • Unit Test: require 'minitest/test'
  • Spec: require 'minitest/spec'
โœ๏ธ Assertion Style:
  • Unit Test: assert_equal expected, actual
  • Spec: _(actual).must_equal expected or expect(actual).must_equal expected
๐Ÿ—๏ธ Structure:
  • Unit Test: Classes with test_ methods
  • Spec: describe blocks with it blocks
๐ŸŽฏ Readability:

Both styles work with Minitest, but the spec style reads more like natural language documentation, making it easier to understand the intended behavior! 

Excellent question! Let me clarify the relationship between TDD/BDD (methodologies) and RSpec/Minitest (testing frameworks):

Happy Testing!