Skip to content
AgileLogics
6 min read

Testing with Minitest

Prerequisites: Classes and objects, Gems and Bundler

A test is code that checks your other code works. Instead of running your program and eyeballing the output, you write down what should happen once, and a tool checks it every time you change something.

Minitest ships with Ruby, so it's the easiest place to start.

The code under test

# cart.rb
class Cart
  attr_reader :items

  def initialize
    @items = []
  end

  def add(name, price)
    raise ArgumentError, "price must be positive" unless price.positive?

    @items << { name:, price: }
  end

  def total
    @items.sum { |item| item[:price] }
  end
end

{ name:, price: } is shorthand for { name: name, price: price } (Ruby 3.1+).

A test file

# cart_test.rb
require "minitest/autorun"
require_relative "cart"

class CartTest < Minitest::Test
  def setup
    @cart = Cart.new
  end

  def test_starts_empty
    assert_equal 0, @cart.total
    assert_empty @cart.items
  end

  def test_total_adds_prices
    @cart.add("book", 12)
    @cart.add("pen", 3)

    assert_equal 15, @cart.total
  end

  def test_rejects_non_positive_price
    error = assert_raises(ArgumentError) { @cart.add("free", 0) }
    assert_equal "price must be positive", error.message
  end
end
$ ruby cart_test.rb
Run options: --seed 12345

# Running:

...

Finished in 0.000812s, 3694.5813 runs/s, 7389.1626 assertions/s.

3 runs, 6 assertions, 0 failures, 0 errors, 0 skips

Each . is a passing test.

  • A test class inherits from Minitest::Test; every method starting with test_ is a test.
  • setup runs before each test, so every test gets a fresh cart.
  • Assertions check results: assert_equal expected, actual, assert, refute, assert_nil, assert_includes, assert_raises.
  • Tests run in random order (the --seed), which catches tests that accidentally depend on each other.

When a test fails

Minitest prints the difference between what you expected and what happened:

  1) Failure:
CartTest#test_total_adds_prices [cart_test.rb:15]:
Expected: 15
  Actual: 12

What to test

Test behavior, not implementation: what goes in and what comes out. Cover the normal case, edge cases (empty input, zero, the boundary of a range), and error cases.

Common mistakes

  • Swapping the arguments: it's assert_equal expected, actual. The wrong order makes failure messages misleading.
  • Tests that depend on each other's leftover state. Use setup to start each test clean.