How to Test with RSpec Tests on Ruby

RSpec Introduction

RSpec is consists of several libraries that are meant to function together but may also be used along with other testing tools such as Cucumber or Minitest. RSpec bases on the following components:

  1. RSpec-core: The spec runner, which includes a robust command-line interface, configurable and customized reporting, and an API for organizing code samples. 3.10 is the latest version.
  2. RSpec-expectations: A straightforward API for expressing expected results of a code example. 3.10 is the latest version.
  3. RSpec-mocks: A test framework that provides various false objects to allow you to manage the environment in which your specs execute precisely. 3.10 is the latest version.
  4. RSpec-rails is an abbreviation for Rails Specification Specification Rails Supports using RSpec instead of Rails’ built-in test framework to test Ruby on Rails apps. Versions available: 5.0

Rspec with Ruby

Rspec is a Ruby testing tool designed for behavior-driven development (BDD). In production applications, it is the most often used Ruby testing library. Even though it includes a highly comprehensive and sophisticated DSL (domain-specific language), it is fundamentally an essential tool that you can get started with quickly.

Kent Beck’s book Extreme Programming Explained, published in 2000, was the first to popularise the concept of test-driven development (TDD). Instead of developing tests for every piece of code that a user has, it operates in a red-green loop:

  1. Create the tiniest test case that corresponds to what needs to program.
  2. Perform the test and observe how it fails. It prompts the user to consider how to write only the code required to pass the test.
  3. To pass the test, write some code.
  4. Execute the tests in your suite. Repeat the 3rd and 4th procedures until all tests pass.
  5. Refactor the new code to make it as basic and obvious as possible while maintaining a green test suite.

This methodology necessitates a “step zero”: pausing to consider the build and how to do it. It’s easy to lose focus, write extraneous code, and get stuck when the user constantly starts implementing. TDD is the foundation for behavior-driven development (BDD). The goal is to write tests as behavior descriptions for the system. It’s about taking a new approach to the same problem, which leads to clearer thinking and easier-to-understand and maintain tests. It is easier to design better implementation code as a result.

Setup Rspec

Make a new directory and paste the code below into the Gemfile.

# Gemfile
source "https://rubygems.org"
gem "rspec"

To install the newest RSpec and any relevant dependencies, open the project directory in the terminal and type bundle install —path.bundle. It would produce something similar to the following:

$ bundle install --path .bundle
Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Using bundler 2.1.4
Fetching diff-lcs 1.3
Installing diff-lcs 1.3
Fetching rspec-support 3.9.2
Installing rspec-support 3.9.2
Fetching rspec-core 3.9.1
Installing rspec-core 3.9.1
Fetching rspec-expectations 3.9.0
Installing rspec-expectations 3.9.0
Fetching rspec-mocks 3.9.1
Installing rspec-mocks 3.9.1
Fetching rspec 3.9.0
Installing rspec 3.9.0
Bundle complete! 1 Gemfile dependency, 7 gems now installed.

Testing

When new users begin testing, they frequently fall into the trap of designing tests that do too much, test too little, and take intense concentration to grasp what is going on. Test-unit, a unit testing framework included in Ruby’s standard library, is used in this example.

def test_making_order
  book = Book.new(:title => "RSpec Intro", :price => 20)
  customer = Customer.new
  order = Order.new(customer, book)
  order.submit
  assert(customer.orders.last == order)
  assert(customer.ordered_books.last == book)
  assert(order.complete?)
  assert(!order.shipped?)
end

It’s worth mentioning that a user would need a tool like Cucumber to construct an outside-in scenario in human language for a complete BDD cycle. It also serves as a high-level integration test, ensuring that the application performs as intended by the user.

RSpec tests are called “specs” (short for “specifications”) and are kept in the project’s spec directory by convention. Make a directory for it in the project as well:

mkdir spec

Let’s begin by writing a string calculator specification.

# spec/string_calculator_spec.rb
describe StringCalculator do
end

The user constantly describes the behavior of classes, modules, and their methods with RSpec. The call block is always used at the top To put specs in context. It can take a class name, in which case the class must already exist, or any string you choose.

As Ruby methods don’t require parenthesis, this file is starting to feel more like an essay than code. That is the intention.

$ bundle exec rspec

The spec fails due to an uninitialized constant StringCalculator error as the class has not been created. Make a new folder called lib:

Mkdir lib
# lib/string_calculator.rb
class StringCalculator
end
# spec/string_calculator_spec.rb
require "string_calculator"
describe StringCalculator do
end

Run Rspec now.

$ bundle exec rspec
No examples found.

Finished in 0.00068 seconds (files took 0.30099 seconds to load)
0 examples, 0 failures

The user has specified our project’s working setup. It provides a functioning feedback loop with tests and application code.

So let’s get started by creating some code.

The string calculator’s most basic operation is to accept an empty string, in which case it may choose to return a zero. The user must first describe the add method.

# spec/string_calculator_spec.rb
describe StringCalculator do
  describe ".add" do
    context "given an empty string" do
      it "returns zero" do
        expect(StringCalculator.add("")).to eq(0)
      end
    end
  end

Another description the user is using block to describe the add class method. The class methods are prefixed with a dot (“.add”), while it prefixes the instance method with a dash (“#add”).

The user uses a context block to indicate the context in which the add method expects to return zero. Technically, context is the same as described, but it is utilized in different locations to help with code readability.

The user describes a specific example with its block, RSpec’s way of saying “test case.” In general, each example should be descriptive and produce a comprehensible phrase when combined with the context. This one translates to “add class method: given an empty string, it returns zero.”

Expected outcomes define using expect().to, and its negative version expects ().not to, they provide a Ruby expression (in this case, StringCalculator. To adequately express an expectation on a piece of code, add(“) is paired with a matcher. The matcher we’re using here is eq, which is a simple equality matcher.

Conclusion

Although this first test may appear insignificant, testing is an essential component of any program. The above example intends to teach the fundamentals of testing with RSpec. Thousands of tests are performed on large programs to ensure that each component is functioning correctly. The more tests a user writes, the more they realize how important they are. Writing a solid test can save you much time in the long run by saving you from having to hunt out an issue.