Mocks and Stubs with Rails' MiniTest
- #Rails
 - #Testing
 - #TDD
 - #Ruby
 
- 2018/12/29
 
Using mocks and stubs in MiniTest for Rails
Hello from the Rails world! I used to write Java and tested with JUnit, but after changing jobs I now use Ruby and PHP. Here is how I use MiniTest—the default unit-testing framework in Rails—to mock and stub things.
What is MiniTest?
- MiniTest ships with Rails as the standard testing framework.
 - Compared with the de facto (?) RSpec, it is lighter.
 - We mainly use it for unit tests.
 
A minimal example looks like this:
test "test case 001" do
  assert_equal 'expected', 'value under test'
end
You put the method call or return value under test on the right-hand side. In this example I used assert_equal, which checks equality. Other handy assertions include:
| Assertion | Description | 
|---|---|
assert | Passes when the argument is truthy | 
assert_empty | Passes when the argument is empty | 
assert_raise | Passes when the specified exception class is raised | 
That is enough for most basic cases, but explore the docs for more.
What is a mock?
- A mock is a stand-in.
 - You can prevent the original logic from running during a test or swap it out with test-only behavior.
 - Unit tests focus on one component, so you often replace other classes or external systems with mock objects.
 
Let’s make a simple mock.
Using MiniTest::Mock
First require MiniTest at the top of your test file:
require 'minitest/autorun'
Now you can mock things. Suppose we have a Const class with a constant VAR:
class Const
  VAR = 'before'
end
You can stub it like this:
test "test case 002" do
  mock = MiniTest::Mock.new
  mock.expect :call, "Value we want during the test", []
  Const.stub :VAR, mock do
    # Inside this block, Const::VAR returns "Value we want during the test".
  end
end
That helps when you are chasing coverage or isolating unit tests.
You can also provide the replacement value directly without MiniTest::Mock:
test "test case 003" do
  Const.stub :VAR, "Value we want during the test" do
    # Within this block, Const::VAR is set to the provided value.
  end
end
Check the official docs for more details.