Back to home

Mocks With Minitest main image

Mocks With Minitest

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

  1. Basic familiarity with Bundler.
  2. Familiarity with reading tests written in RSpec.
  3. Familiarity with the Pry Gem.

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, MiniTest ships with never versions of Ruby, so there may be no need for any other installation.

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.

  1. The test of what we would actually expect.
  2. A test that mocks out an instance method Person.new(...).describe_person to return different values.
  3. 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

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on workingoutloud.dev, Den Dribbles and LandPad .

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.