Minitest Basics — Your First Ruby Tests
Minitest is Ruby’s built-in testing framework. Unlike RSpec’s BDD style, Minitest stays close to Ruby’s core, making it lighter and faster. If you’re new to testing or want a minimal setup, Minitest is perfect.
Why Minitest?
Minitest ships with Ruby—no extra installation needed. It provides everything you need: unit tests, spec-style tests, mocking, and benchmarking. Many gems use Minitest for their own test suites because it’s fast and integrates seamlessly.
Your First Minitest
Create a test file and write your first test:
# test/calculator_test.rb
require 'minitest/autorun'
class CalculatorTest < Minitest::Test
def test_add_returns_sum_of_two_numbers
calculator = Calculator.new
assert_equal 5, calculator.add(2, 3)
end
end
Run it with ruby test/calculator_test.rb. Minitest automatically runs any method starting with test_.
Assertions
Minitest provides plain assertions that read like method calls:
def test_assertions
# Equality
assert_equal expected, actual
# Truthiness
assert true
refute false
# Nil checks
assert_nil nil
refute_nil "hello"
# Type checks
assert_instance_of String, "hello"
assert_kind_of Numeric, 42
# Collection checks
assert_includes [1, 2, 3], 2
assert_respond_to "hello", :upcase
end
Expectations (Spec Style)
If you prefer RSpec’s expect syntax, enable expectations:
require 'minitest/autorun'
require 'minitest/spec'
describe Calculator do
it 'adds two numbers' do
calculator = Calculator.new
_(calculator.add(2, 3)).must_equal 5
end
it 'raises on invalid input' do
calculator = Calculator.new
_(-> { calculator.add("a", "b") }).must_raise TypeError
end
end
The _() wrapper converts values into Minitest::Spec expectations.
Setup and Teardown
Use setup and teardown for common test preparation:
class UserTest < Minitest::Test
def setup
@user = User.new(name: "Alice", email: "alice@example.com")
end
def teardown
User.delete_all
end
def test_user_has_name
assert_equal "Alice", @user.name
end
end
Test Fixtures
For more complex setup, define fixtures:
class OrderTest < Minitest::Test
fixtures :users, :products
def test_order_belongs_to_user
order = Order.create(user: users(:alice), product: products(:book))
assert_equal users(:alice), order.user
end
end
Mocking and Stubbing
Minitest includes mocking support:
def test_charges_payment_gateway
payment_gateway = Minitest::Mock.new
payment_gateway.expect :charge, true, [100]
processor = OrderProcessor.new(payment_gateway)
processor.charge_order(order_with_total(100))
payment_gateway.verify
end
Stub methods with stub:
def test_uses_cached_data
Cache.stub :get, "cached value" do
result = DataFetcher.fetch(:users)
assert_equal "cached value", result
end
end
Test Organization
Group related tests in classes. Each class is a test suite:
# test/models/
require 'minitest/autorun'
class UserTest < Minitest::Test
# Tests for User model
end
class ProductTest < Minitest::Test
# Tests for Product model
end
Run specific test classes:
ruby test/user_test.rb
ruby test/models/product_test.rb
Running Tests
Minitest runs tests automatically when you require ‘minitest/autorun’. Customize output with flags:
# Verbose output
ruby test/test.rb -v
# Run specific test method
ruby test/test.rb -n test_add_returns_sum
# Run tests matching a pattern
ruby test/test.rb -n /test_add/
Continuous Testing
Speed up your development with continuous testing. The minitest-reporters gem gives you color-coded output and progress indicators:
# Gemfile
group :test do
gem 'minitest-reporters'
end
Configure it in your test helper:
require 'minitest/reporters'
Minitest::Reporters.use!
Now you’ll see green dots for passing tests and red F’s for failures, plus execution time for each test.
Testing Strategies
Good tests follow the FIRST principles: Fast, Independent, Repeatable, Self-validating, Timely. Minitest helps you achieve these by keeping tests simple and fast.
Write tests before code (TDD) to clarify what you’re building. Start with a failing test, then write the minimum code to pass it. This approach often reveals design issues early.
Minitest vs RSpec
Choose Minitest when:
- You want minimal dependencies
- Speed matters for large test suites
- You prefer assertion-style tests
- You’re testing simple scripts or gems
Choose RSpec when:
- You prefer behavior-driven syntax
- Your team already knows RSpec
- You need advanced mocking features
- Readable specs are more important than speed
Summary
Minitest gives you a lightweight, fast testing foundation. Its assertion style is explicit and easy to understand. Start with Minitest to build testing habits, then explore RSpec if you need more expressive syntax later.
See Also
- Testing with RSpec — Learn RSpec for BDD-style testing in Ruby
- Enumerable#inject — The reduce method used in many test scenarios
- Error Handling in Ruby — Understanding exceptions for testing error cases