Book Image

RSpec Essentials

By : Mani Tadayon
Book Image

RSpec Essentials

By: Mani Tadayon

Overview of this book

This book will teach you how to use RSpec to write high-value tests for real-world code. We start with the key concepts of the unit and testability, followed by hands-on exploration of key features. From the beginning, we learn how to integrate tests into the overall development process to help create high-quality code, avoiding the dangers of testing for its own sake. We build up sample applications and their corresponding tests step by step, from simple beginnings to more sophisticated versions that include databases and external web services. We devote three chapters to web applications with rich JavaScript user interfaces, building one from the ground up using behavior-driven development (BDD) and test-driven development (TDD). The code examples are detailed enough to be realistic while simple enough to be easily understood. Testing concepts, development methodologies, and engineering tradeoffs are discussed in detail as they arise. This approach is designed to foster the reader’s ability to make well-informed decisions on their own.
Table of Contents (17 chapters)
RSpec Essentials
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Writing specs with RSpec


We have discussed a lot of theory; now, let's start applying it. We'll write a few specs for the AddressValidator module defined below:

module AddressValidator
  FIELD_NAMES = [:street, :city, :region, :postal_code, :country]
  VALID_VALUE = /^[A-Za-z0-9\.\# ]+$/
  class << self
    def valid?(o)
      normalized = parse(o)
      FIELD_NAMES.all? do |k|
        v = normalized[k]
        !v.nil? && v != "" && valid_part?(v)
      end
    end

    def missing_parts(o)
      normalized = parse(o)
      FIELD_NAMES - normalized.keys
    end

    private

    def parse(o)
      if (o.is_a?(String))
        values = o.split(",").map(&:strip)
        Hash[ FIELD_NAMES.zip(values) ]
      elseif (o.is_a?(Hash))
        o
      else
        raise "Don't know how to parse #{o.class}"
      end
    end

    def valid_part?(value)
      value =~ VALID_VALUE
    end
  end
end

We'll store the code above in a file called address_validator.rb. Let's start with a couple of simple tests in this chapter. In the next chapter, we'll explore a few different ways to expand and improve these tests, but for now we'll just focus on getting up and running with our first real RSpec tests.

We'll put the following code in a file called address_validator_spec.rb in the same folder as address_validator.rb:

require 'rspec'
require_relative 'address_validator'

describe AddressValidator do
  it "returns false for incomplete address" do
    address = { street: "123 Any Street", city: "Anytown" }
    expect(
      AddressValidator.valid?(address)
    ).to eq(false)
  end

  it "missing_parts returns an array of missing required parts" do
    address = { street: "123 Any Street", city: "Anytown" }
    expect(
      AddressValidator.missing_parts(address)
    ).to eq([:region, :postal_code, :country])
  end
end

Now, let's run RSpec (make sure you have it installed already!) like this:

That's it. We used a couple of options to format the output, which is self-explanatory. We'll dig deeper into how to run specs with various options in future chapters. For now, we've accomplished our goal of running RSpec for a couple of unit tests.

Now is a good time to reflect on the concepts of testability and the unit of code. How testable is our AddressValidator module? Do you see any potential problems? What about the units we've tested? Are they isolated and modular? Do you see any places where we could do better? Take some time to review the code and think about these questions before moving on to the next section.