Creating a RSpec Stub for Sending SMS Messages
In this video we'll create a RSpec stub for our SMS sending tool. Because we'll eventually call the SMS module from a rake task we won't use this stub, however it's a best practice to use stubs for API connections and I wanted to show you how to do it effectively, even if we're not going to use it for this specific application.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

In this guide, we are going to create a RSpec stub for sending a SMS message, and this requires a decent amount of configuration. I'm going to open my guide and we'll go through each step.

First off, we are going to create a mock or fake stub. This is important, especially if your application is going to contact an outside API for implementing its functionality. Frequent contacts to APIs will slow your test, and it can sometimes even block you out, especially if you reach your usage limit. Let's say, for example, you're allowed only hundred API calls a day. When you run ten tests, you'll reach that limit in no time, and cannot test further. Additionally, you'll never be able to work offline if you use real test stubs. To avoid these problems, it's always good to have mock or fake stubs.

Create a file called fake_sms.rb in your lib folder and have this code:

# lib/fake_sms.rb

module FakeSms
  Message = Struct.new(:message, :message)
  @messages = []

  def self.send_sms(number:, message:)
    @messages << Message.new(number, message)
  end

  def self.messages
    @messages
  end
end

Here, we are creating a module called FakeSms, and using a data structure called Struct. This Struct object is the best way to mimic a database. We are passing the number and message as its arguments.

When we run this module, we are going to create an object called a Message that comes with a number and message every time and pass it to an array called messages. Later, our tests can see what's inside messages.

Next, let's config our rspec tests. Open spec_helper.rb in your spec folder, as this is where we put all configuration information. I want to remove all the comments before adding the code because I think it's confusing.

Let's add the new code.

# spec/spec_helper.rb

RSpec.configure do |config|
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end

  config.before(:each) do
    stub_const("SmsTool", FakeSMS)
  end

  config.shared_context_metadata_behavior = :apply_to_host_groups
end

In this code, we are saying that before each config, we are going to stub the constant SmsTool for a FakeSMS. Essentially, we are asking the tests to check before running everything if there is a call to SmsTool, and if there is a call, we want the test to swap SmsTool with FakeSMS. If you see, we have a method called send_sms in our FakeSMS module, just like our SmsTool to mimic this functionality.

Next, let's test it out on our test environment in the Rails console. You can do that with the command:

rails c -e test

We are going to replicate exactly what we did in the previous lesson to see if the mock is working. So, the command will be:

Let's run our FakeSMS module with this command:

FakeSMS.send_sms(number: 234234, message: "asdfasdf")

See how this struct acts as a database to store multiple messages. This is the closest we are going to get to mimicking an API call.

Resources