DEV Community

Cover image for #Writing Tests for a Ruby Application
Pamela Torres-Rocca
Pamela Torres-Rocca

Posted on

#Writing Tests for a Ruby Application

Recently, I went back to the first CLI application that I had written in order to test the behavior of the application. I had recently created a new version of this application to support html changes to the website that it scrapes. The changes to the site were preventing the application from scraping the desired appointment time and location from the site. After the update to the application, I wanted to make sure that the behavior was still what I needed it to do.
To test behavior I used a gem called rspec that tests code in Ruby. The version is 3.10.0 and I used the documentation at https://relishapp.com/rspec/rspec-mocks/v/3-10/docs/basics as well as Stack Overflow for some examples of mocks and stubs. To get a good overview of testing using rspec I completed sections of the LinkedIn elearning course Ruby: Testing with RSpec to learn basic syntax.

I wrote a separate test file for each class of the component. Since I wanted to test the behavior of individual methods within the class, I needed to isolate each method and which was challenging as each method typically called an additional method within itself. In order to prevent the program from continuing to run while testing an individual method, I used test doubles which are objects that stand in for other objects. Each class was dependent on other classes, so I needed to write doubles for the other dependent classes in each test file to ensure that I was only testing the behavior of the current class.

Test Doubles for Classes


RSpec.describe Urgentcare::CLI do 

    let!(:cliInstance) {Urgentcare::CLI.new}
    let!(:office) {Urgentcare::Office}
Enter fullscreen mode Exit fullscreen mode

The specific kinds of test doubles that I used were mocks which replicate the method that it is standing in for. You need to explicitly spell out the behavior that you need the mock to have. I also used stubs which gave an object behavior. For example I created an Office double and gave it data to return when this instance is called.

Office Class Double with Test Data

let!(:office) {Urgentcare::Office}

    before(:each) do
      @index = 0
      @new_array = []                
      @offices = @new_array << office.new("Worcester Greenwood St", "https://www.carewellurgentcare.com/urgent-care-appointment-form-worcester-greenwood/", "2:00 PM Friday, September 17 (EDT)  ", "(617) 804-6293 ")
    end
Enter fullscreen mode Exit fullscreen mode

This Office double was used to test the output displayed to the user in the following spec:

it "displays office details when valid office selected" do
      allow(cliInstance).to receive(:list).and_return("List")
      cliInstance.instance_variable_set(:@index, 0)
      expect { cliInstance.office_details }.to output(a_string_starting_with(" \n---\nOffice Name: Worcester Greenwood St\nOffice Number: (617) 804-6293 \nOffice URL: https://www.carewellurgentcare.com/urgent-care-appointment-form-worcester-greenwood/\nOffice Next Available Appointment: 2:00 PM Friday, September 17 (EDT)")).to_stdout
    end
Enter fullscreen mode Exit fullscreen mode

Strategic use of object doubles in testing isolates the specific class and method behavior that you want to test. In the example of the scraper it also allows for testing without requiring the use of the internet.

Top comments (0)