Mocks With Minitest
Published: Apr 6, 2022
Last updated: Apr 6, 2022
This post will overview how you can use Minitest mocks within your tests for both class and instance methods.
Source code can be found here
Prerequisites
Getting started
We will create the project directory demo-minitest-mocking
and use Bundler to initialize the project:
$ mkdir demo-minitest-mocking $ cd demo-minitest-mocking $ mkdir lib test $ touch lib/car.rb lib/person.rb test/test_car.rb Rakefile
As noted in this blog post
We are going to test some contrived classes where an instance of Car
has a Person
as a driver and calls a contrived class method Person.describe
when calling its own method. Hopefully this will make more sense as we write out the two classes.
Writing the Person class
In lib/person.rb
, add the following:
class Person attr_reader :name, :age class << self def describe 'I am the representation of a person' end end def initialize(name, age) @name = name @age = age end def describe_person [@name, @age] end end
Effectively we are initializing the person with a name
and age
property, having a describe_person
instance method return a tuple of the name and age, and we have also added a class method to describe the Person
class.
Next, we need to write our code for the Car
class.
The Car Class
In lib/car.rb
:
require 'person' class Car attr_accessor :driver def initialize @driver = Person.new('John Doe', 30) end def describe_driver name, age = @driver.describe_person description = Person.describe [name, age, description] end end
In this class, we always designate the driver as a Person
instance. This is forced and contrived, but you will see how we can mock the Person
class in the next section.
We also have a describe_driver
instance method that returns a tuple of the driver's name, age, and the description of the Person
class.
Writing our tests
With how the current code works, we expect Car.new.describe_driver
to always return ['John Doe', 30, 'I am the representation of a person']
because the code is hardcoded.
We will write a test to demonstrate this, but then the following two tests will demonstrate how we can mock them out.
In test/test_car.rb
, add the test code:
require 'minitest/autorun' require 'car' require 'person' describe Car do describe '#describe_driver' do it 'should return information on the driver provided' do result = Car.new.describe_driver expectation = ['John Doe', 30, 'I am the representation of a person'] assert_equal(expectation, result) end # This test will mock the result of Person.new(...).describe_person() it 'should return information from the mocked person instance methods' do mock = MiniTest::Mock.new mock.expect(:describe_person, ['Jane Doe', 20]) Person.stub(:new, mock) do result = Car.new.describe_driver expectation = ['Jane Doe', 20, 'I am the representation of a person'] assert_equal(expectation, result) end mock.verify end # This test will mock the result of Person.description() # Note that you need to mock.expect(:call) for class methods it 'should return information from the mocked person class method' do mock = MiniTest::Mock.new mock.expect(:call, 'I am another representation of a person') Person.stub(:describe, mock) do result = Car.new.describe_driver expectation = ['John Doe', 30, 'I am another representation of a person'] assert_equal(expectation, result) end mock.verify end end end
We write three tests in the above.
- The test of what we would actually expect.
- A test that mocks out an instance method
Person.new(...).describe_person
to return different values. - A test that mocks out a class method
Person.description
to return a different description.
The important thing to note with the class methods is that you will mock :call
, which itself is a little confusing when you compare how the mocks for instance methods work.
Summary
Today's post demonstrated how to mock both class methods and instance methods in Minitest.
Admittedly, the code is very contrived and the Minitest mocking approach isn't very familiar if you are used to other test runners like Jest, but it is a useful reference for when you will need it.
Resources and further reading
Photo credit: benostrower
Dennis O'Keeffe
Melbourne, Australia
1,200+ PEOPLE ALREADY JOINED ❤️️
Get fresh posts + news direct to your inbox.
No spam. We only send you relevant content.
Mocks With Minitest
Introduction