Ruby Minitest
last modified October 18, 2026
Minitest is the standard testing library bundled with Ruby. It provides a small,
fast API for writing unit tests: test classes inherit from
Minitest::Test, test methods are named test_*, and
assertions verify results. This guide shows how to write and run tests with
Minitest, using a set of short examples that build from basic assertions to
testing a class and reading failure output.
Note on output: the test runner prints a random seed and a timing line
("Finished in ...") that vary between runs. The examples below are run with
--seed 42 so the order of tests is fixed. On your machine the
timing numbers will differ, and the seed will differ if you omit the flag.
Basic Assertions
The require 'minitest/autorun' line loads Minitest, which ships with Ruby, so no gem installation is needed. Test cases subclass Minitest::Test, and every public method whose name starts with test_ is run as a separate test. This example uses assert, assert_equal, assert_nil, and refute.
#!/usr/bin/env ruby
require 'minitest/autorun'
class BasicTest < Minitest::Test
def test_addition
assert_equal 4, 2 + 2
end
def test_string_is_truthy
assert "hello"
end
def test_nil_value
assert_nil nil
end
def test_inequality
refute 1 == 2
end
end
assert_equal takes the expected value first and the actual value second. assert passes for any truthy value, assert_nil checks for nil, and refute is the negation of assert. The summary line reports the number of runs, assertions, failures, errors, and skips.
$ ./ex1_basic.rb --seed 42 Run options: --seed 42 # Running: .... Finished in 0.001119s, 3574.2145 runs/s, 3574.2145 assertions/s. 4 runs, 4 assertions, 0 failures, 0 errors, 0 skips
Setup and Teardown
The setup method runs before each test method and the teardown method runs after it. Instance variables set in setup are available to every test, which avoids repeating the same fixture code. The puts calls make the order visible.
#!/usr/bin/env ruby
require 'minitest/autorun'
class SetupTest < Minitest::Test
def setup
@numbers = [3, 1, 2]
puts "setup runs before each test"
end
def teardown
puts "teardown runs after each test"
end
def test_sorted
assert_equal [1, 2, 3], @numbers.sort
end
def test_size
assert_equal 3, @numbers.size
end
end
For each test, Minitest calls setup, then the test method, then teardown. Test methods run in a random order controlled by the seed, so tests should never depend on each other.
$ ./ex2_setup.rb --seed 42 Run options: --seed 42 # Running: setup runs before each test teardown runs after each test .setup runs before each test teardown runs after each test . Finished in 0.001057s, 1891.4998 runs/s, 1891.4998 assertions/s. 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
Testing a Class
This example tests a small Calculator class. The setup method creates a fresh instance for each test. The assert_raises assertion checks that a block raises the expected exception class.
#!/usr/bin/env ruby
require 'minitest/autorun'
class Calculator
def add(a, b)
a + b
end
def divide(a, b)
raise ZeroDivisionError, "cannot divide by zero" if b.zero?
a / b
end
end
class CalculatorTest < Minitest::Test
def setup
@calc = Calculator.new
end
def test_add
assert_equal 5, @calc.add(2, 3)
end
def test_divide
assert_equal 2, @calc.divide(10, 5)
end
def test_divide_by_zero
assert_raises(ZeroDivisionError) { @calc.divide(1, 0) }
end
end
assert_raises passes only when the block raises ZeroDivisionError; if nothing is raised, or a different exception is raised, the test fails. All three tests pass with seed 42.
$ ./ex3_calculator.rb --seed 42 Run options: --seed 42 # Running: ... Finished in 0.001477s, 2030.6493 runs/s, 2030.6493 assertions/s. 3 runs, 3 assertions, 0 failures, 0 errors, 0 skips
Checking Collections and Strings
assert_includes checks whether a collection contains an element or a string contains a substring. Here it is used on an array and on a string, both of which respond to include?.
#!/usr/bin/env ruby
require 'minitest/autorun'
class StringUtilsTest < Minitest::Test
def test_includes_element
assert_includes %w[ruby python go], "ruby"
end
def test_includes_substring
assert_includes "hello world", "world"
end
end
Both tests pass, giving 2 runs and 4 assertions in total. The summary line reports the counts; the dot on each line of the progress row marks a passing test.
$ ./ex4_strings.rb --seed 42 Run options: --seed 42 # Running: .. Finished in 0.000950s, 2104.4701 runs/s, 4208.9402 assertions/s. 2 runs, 4 assertions, 0 failures, 0 errors, 0 skips
A Failing Assertion
This test is intentionally wrong: 2 + 2 is 4, not 5. Running it shows how Minitest reports a failure, with the test name, file and line, and the expected and actual values.
#!/usr/bin/env ruby
require 'minitest/autorun'
class FailingTest < Minitest::Test
def test_wrong_sum
assert_equal 5, 2 + 2
end
end
The F in the progress row marks the failure. The process exits with status 1, which is what a CI system uses to detect failing tests. The file and line in the failure header point to the failing assertion.
$ ./ex5_failing.rb --seed 42 Run options: --seed 42 # Running: F Finished in 0.000933s, 1072.0251 runs/s, 1072.0251 assertions/s. 1) Failure: FailingTest#test_wrong_sum [ex5_failing.rb:6]: Expected: 5 Actual: 4 1 runs, 1 assertions, 1 failures, 0 errors, 0 skips
List all Ruby tutorials.
Author
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.