How to Test Ruby Modules With Rspec

Jul 20, 2018 - 3 min read
How to Test Ruby Modules With Rspec
Share

What are Ruby modules

Modules are a way to share code either by re-using your own code, or using third party libraries (i.e., gems).

They help you group together methods, classes, and constants inside a namespace so that they are isolated from other modules.

module Generic
  def self.greeting
    puts "Hello World"
  end
end

module Specific
  def self.greeting
    puts "Hello John"
  end
end

Generic.greeting
Specific.greeting

# output

Hello World
Hello John

In the example above, even though the two methods have the same names, you can still use both because they belong to different namespaces.

How are Ruby modules used

You can use modules on their own (just as you saw in the previous example), to group methods that don’t really fit anywhere else. To call a module method, you specify the name of the module, and the name of the method, separated by a dot. Like this: MyModule.my_method.

But you can also include modules into classes so that those classes inherit all the module’s instance methods.

module Greet
  def greeting
    puts "Hello World"
  end
end

class Person
  include Greet
end

Person.new.greeting

# output

Hello World

How to test a Ruby module with RSpec

For module methods (i.e., those declared on self), the tests are similar to class method tests.

require 'spec_helper'

module MyMath
  def self.number
    5
  end
end

RSpec.describe MyMath do
  it 'returns five' do
    expect(MyMath.number).to eq(5)
  end
end

But when you have a module that you include in other classes (i.e., it contains instance methods) the way you test it might not be obvious. An example should help with this challenge.

require 'spec_helper'

module MyMath
  def number
    5
  end
end

class DummyClass
  include MyMath
end

RSpec.describe MyMath do
  it 'returns five' do
    dc = DummyClass.new
    expect(dc.number).to eq(5)
  end
end

Because DummyClass includes the MyMath module, it behaves like any other class that would include it. So by having a test that covers DummyClass, you’ve covered all those other classes that include the module.

Another way you can do it, without including the module is to extend an object.

require 'spec_helper'

module MyMath
  def number
    5
  end
end

class DummyClass
end

RSpec.describe MyMath do
  it 'returns five' do
    dc = DummyClass.new
    dc.extend(MyMath)
    expect(dc.number).to eq(5)
  end
end

And lastly, instead of polluting the global namespace with a dummy class like that, you can use let.

require 'spec_helper'

module MyMath
  def number
    5
  end
end

RSpec.describe MyMath do
  let(:dummy_class) { Class.new { extend MyMath } }

  it 'returns five' do
    expect(dummy_class.number).to eq(5)
  end
end

Testing modules in Ruby should be easier now that you’ve see a few examples.

12 Project Ideas
Cezar Halmagean
Software development consultant with over a decade of experience in helping growing companies scale large Ruby on Rails applications. Has written about the process of building Ruby on Rails applications in RubyWeekly, SemaphoreCI, and Foundr.