Ruby Testing with Minitest

Testing is built into Ruby — Minitest comes with the standard library. Good tests give you confidence to refactor.

Your First Test

Ruby
# calculator.rb
class Calculator
  def add(a, b)
    a + b
  end

  def divide(a, b)
    raise ArgumentError, "Cannot divide by zero" if b == 0
    a.to_f / b
  end
end
Ruby
# test_calculator.rb
require "minitest/autorun"
require_relative "calculator"

class CalculatorTest < Minitest::Test
  def setup
    @calc = Calculator.new
  end

  def test_add
    assert_equal 5, @calc.add(2, 3)
    assert_equal 0, @calc.add(-1, 1)
  end

  def test_divide
    assert_equal 2.5, @calc.divide(5, 2)
  end

  def test_divide_by_zero
    assert_raises(ArgumentError) { @calc.divide(1, 0) }
  end
end

Run: ruby test_calculator.rb

Common Assertions

Ruby
assert_equal expected, actual        # ==
assert_nil value                     # value.nil?
assert_empty collection              # collection.empty?
assert_includes collection, item     # collection.include?(item)
assert_in_delta 3.14, calc.pi, 0.01 # approximate float comparison
assert_raises(SomeError) { ... }     # block must raise the error

Test-Driven Development (TDD)

  1. Red — write a failing test
  2. Green — write the minimum code to pass
  3. Refactor — improve the code while tests stay green
Ruby
def test_fizzbuzz
  assert_equal "FizzBuzz", fizzbuzz(15)
  assert_equal "Fizz", fizzbuzz(3)
  assert_equal "Buzz", fizzbuzz(5)
  assert_equal "7", fizzbuzz(7)
end

def fizzbuzz(n)
  return "FizzBuzz" if (n % 15).zero?
  return "Fizz" if (n % 3).zero?
  return "Buzz" if (n % 5).zero?
  n.to_s
end

Tips

  • Write tests before writing code (TDD).
  • Keep tests fast — slow tests don't get run.
  • One assertion per test method (ideally).

Next: metaprogramming.