Testing Ruby with RSpec: The Complete Guide
4.6 (80 ratings)
Course Ratings are calculated from individual students’ ratings and a variety of other signals, like age of rating and reliability, to ensure that they reflect course quality fairly and accurately.
10,764 students enrolled

Testing Ruby with RSpec: The Complete Guide

Master the art of test-driven development in Ruby using the popular RSpec Gem. No previous testing experience needed!
Bestseller
4.6 (80 ratings)
Course Ratings are calculated from individual students’ ratings and a variety of other signals, like age of rating and reliability, to ensure that they reflect course quality fairly and accurately.
10,764 students enrolled
Created by Boris Paskhaver
Last updated 1/2019
English
English [Auto-generated]
Current price: Free Original price: $199.99 Discount: 100% off
30-Day Money-Back Guarantee
This course includes
  • 7.5 hours on-demand video
  • 3 articles
  • 2 downloadable resources
  • Full lifetime access
  • Access on mobile and TV
  • Assignments
  • Certificate of Completion
Training 5 or more people?

Get your team access to Udemy's top 3,000+ courses anytime, anywhere.

Try Udemy for Business
What you'll learn
  • Utilize test-driven development principles to design and implement clean test specs in Ruby
  • Master the syntax and structure of RSpec, the most popular Ruby Gem for testing

  • Reduce dependencies in your test suite by mocking objects with class and instance doubles

  • Explore the wide collection of RSpec matchers available to test your code
Course content
Expand all 58 lectures 07:30:04
+ Introduction
24 lectures 02:54:05

Welcome to the course! This lecture offers a quick introduction to the RSpec Gem as well as the benefits of testing. The various pieces of the library -- the core runner, expectations, and mocks -- are also introduced.

Preview 13:03

Unit tests target a specific "unit" or piece of an application, such as a single class or method. They create isolation between coupled components to ensure each piece stands by itself. In comparison, end-to-end tests test an application or a large feature as a whole. Integration tests fall somewhere in the middle. In this lesson, we talk extensively about these types of tests and introduce the testing pyramid.

Unit Tests vs End-to-End (E2E) Tests
09:16

This lecture offers a written tutorial for installing the Homebrew package manager, the rbenv Ruby version manager, and a modern version of Ruby on a macOS operating system. Windows users are advised to install Ruby through the RubyInstaller.org website.

Setup rbenv / Ruby on MacOS
01:10

Ruby ships with a package manager called Gem. In this lesson, we utilize it to download the RSpec testing library.

Installing RSpec
03:11

Visual Studio Code is a popular open-source text editor that is supported by Microsoft. This lesson covers the installation of the software on a macOS machine as well as the setup of the recommended Ruby extension for syntax highlighting. Windows users are advised to follow the instructions on the VSCode website to setup the app on their computers. If you prefer another text editor, that is totally fine as well.

Installing Visual Studio Code for MacOS
00:51

The rspec --init command creates a base skeleton for an RSpec project. It creates a spec_helper.rb file where high-level, global RSpec settings for the project can be declared. There are some recommended settings that can be enabled by removing the =begin and =end lines in the file.

Starting a Project with rspec --init
10:17

Download the complete course files here!

Download Course Files (Optional)
00:28

Test-driven development (TDD) is a testing paradigm that argues that tests should be written first, before the code. This approach forces the developer to think critically about the implementation of the feature, one method at a time. This lesson describes the red-green-refactor pattern for practicing TDD. Red means a failing spec, green means a passing spec, and refactor means optimizing the code for clarity and efficiency.

Test-Driven Development
05:28

The describe method on the top-level RSpec module creates an example group. An example group contains one or more examples. An example is the technical RSpec term for a test. In this lesson, we walk through the basic syntax and structure of setting up a sample example group (hey, that rhymes!)

The describe Method
04:42

The it method creates an example (i.e. a focused test). The it method accepts a string -- ideally, it should be one that makes the example read like a sentence (i.e. it "should shuffle the deck" or it "can communicate with database"). After the string argument, pass the method a block. The block will contain the assertions for that example.

The it Method
05:33

The expect method accepts what will be evaluated --it can be an object, a class, a method, or a plain Ruby expression like 1 + 1. The method returns an object that includes a to method, which is invoked with a matcher. A matcher is a type of assertion; there are various matchers in RSpec for equality, inequality, identity, inclusion and more. In this lesson, we create a sample Card object and write our first expectation for it.

The expect and eq Methods
08:01
The RSpec expectation syntax has a little bit of a learning curve. In this assignment, you'll practice using the describe, it and expect methods to make some basic mathematical assertions.
The describe, it and expect Methods
1 question

The rspec command in the Terminal can be followed with a path to a spec file's location. The command starts the RSpec test runner. The Terminal output includes a list of all examples that failed, including the line number that encountered an error or inconsistency. In this lesson, we read over the output and prepare to fix our failing specs.

Reading Failures
07:29

It's time to make the Card class a reality! In this lesson, using our failing specs to guide us, we define a new Card class with a type attribute and a public reader method. It's important to not speed ahead and try to fix everything at once. Use each failure from the RSpec output to determine the next line of code to write. Fix one error, then run the rspec command again, and repeat.

Making the Specs Pass
08:57

The time has come to challenge your knowledge of the course's material! This quiz dives into some of the higher-level concepts we've talked about so far (test-driven development, the testing pyramid) as well as RSpec-specific methods like describe, it, and expect.

QUIZ: TDD and RSpec Methods
9 questions

An example group can contain multiple examples. Some testing advocates argue that each example should only have one assertion. In this lesson, we expand the Card class to have a rank and a suit and write the corresponding specs.

Multiple Examples in Example Group
08:01

In this lesson, we continue the practice of using our failing specs to drive the development of the code. We update the Card class to have two initialize arguments, two reader methods, and two instance variables. We also discuss some of the drawbacks of our current examples, particularly the duplication.

Fixing Failing Specs Again
08:23
We've now explored the basics of using test-driven development (TDD) to write our code. In this lesson, you'll practice these concepts by writing some Ruby code for some failing specs.
Making Specs Pass
1 question

Multiple examples in a test suite often rely on the same piece of data or a common object. Duplicating the code to create or access that object in each example creates a lot of duplication. To DRY up the code, this lesson introduces before hooks and instance variables. A hook is a piece of code that runs automatically at a specific time during testing. By default, the before hook executes a block of code before each example. Within the block, we assign values to instance variables to preserve values once the block execution ends. These instance variables are then available to be used within any examples defined below.

Reducing Duplication - Before Hooks and Instance Variables
10:58

The block passed to the describe method provides a regular environment for Ruby expressions. We can define helper methods there to be invoked by the examples. Like a before block, this approach also creates separation between the examples.

Reducing Duplication: Helper Methods
04:12

In this lesson, we discuss the limitations of a helper method approach. Subsequent calls to the same helper method in an example will return a new object each time. This makes it impossible to mutate a single object's state without using extra variables.

Problems With Mutation
06:03

The let method defines a memoized, lazy-loaded variable that is available to all examples in the current context. The method accepts a symbol for the name of the variable and a block for the value that variable should be assigned. Lazy-loaded means the variable will not be declared until it is used in a specific example. Memoized means multiple references to the variable in the same example will not require a reevaluation of the block passed to the let method.

Reducing Duplication: The let Method
15:05

To have RSpec display a custom error message when an expectation fails, pass a string as the second argument to the to method. In this lesson, we compare the different Terminal outputs for the default error message and our custom one.

Custom Error Messages
04:39

Test your knowledge of the concepts introduced in the previous lessons! This quiz tackles the topics of instance variables, helper methods, the let method, as well as broader concepts like memoization and lazy-loading.

QUIZ: Removing Duplication
5 questions

describe method invocations can be nested inside other describe blocks. This is done to provide context about the specific circumstance or situation that an example is being run. context is an available alias for the describe method -- it can be used in the same fashion. In this lesson, we create nested describe blocks to test the even? predicate method in Ruby.

The context Method and Nested Describes
08:17

A hook allows the developer to run code during certain moments or events in the test suite's execution. The before and after run a block of code before or after a given criteria. When given a symbol of :example, the hook will run before / after each individual test. When given a symbol of :context, the hook will run once before / after all tests in the current block. In a real-life scenario, :context is used for high-level setup and teardown operations like connecting and disconnecting to a database (which is an expensive operation that you don't want to perform for each test).

before and after Hooks
09:07

Hooks gain an additional layer of complexity when describe / context blocks are nested within other describe / context blocks. The before(:context) hooks runs once before all tests in the current context (i.e. the current block). The before(:example) hook runs once before each test in the current context (which includes all nested blocks as well). If there is a before(:example) hook defined at multiple levels, each one will run in sequence, starting from the top-most block and proceeding downwards.

Preview 12:00
Test your knowledge of RSpec hooks in both a regular and nested context!
Single Context Hooks
1 question
This is a tough one! Test your knowledge of before and after hooks when dealing with multiple nested contexts.
Multi-Context Hooks
1 question

let variables can be set to different values in nested blocks. Ruby  / RSpec will search for the name in the current scope, then proceed upwards if it is unable to find it. Instead of using multiple variable names and adding confusion, it's much more elegant to reuse the let variable and assign it new, relevant values in each testing context.

Nested Logic: Overwriting Let Variables
08:53
+ Subjects, Shared Examples, and Shared Context
6 lectures 42:20

The subject helper method lazily instantiates an instance of the class under test. This offers the developer several advantages including (1) one less let variable and (2) shorthand syntax for expectations that we'll discuss later. By default, subject assumes the class will have no initialization arguments. Within the same example, subject will memoize / cache the object when it's used multiple times. Between different examples, subject will instantiate a fresh object. In this lesson, we utilize subject to test a Ruby hash.

Implicit Subject
07:37
Use RSpec's built-in subject helper method to access an instance of the class under test. Practice the syntax introduced in the previous lesson.
Implicit Subject
3 questions

The subject method can be invoked outside of any example. The last evaluation of the block passed to the method will serve as its return value. This allows the developer to instantiate a custom object from the class under test to serve as the base "subject" for testing. A subject declared in an outer scope (i.e. an outer block) will be available to all inner, nested blocks.

Explicit Subject
05:38
Overwrite RSpec's default subject with an explicit instance of the class under test. Practice the syntax introduced in the previous lesson.
Explicit Subject
1 question

When a class is passed as an argument to the describe method, the class itself becomes available via the described_class method. It is advantageous to use described_class whenever the class is referenced because it makes the specs more adaptable to changes in business logic, such as the renaming of the class under test.

described_class
06:13

The use of either an implicit or explicit subject grants access to a special one-liner syntax for writing an example. First, the it method is passed a block without a string argument. Next, the method is_expected is invoked as a replacement for the expect syntax. Finally, a regular RSpec matcher (such as eq) is attached to the end. In this lesson, we demonstrate both syntactical options side by side.

One-Liner-Example-Syntax
05:07

The RSpec.shared_examples method is used to define commonly used examples that can be injected into multiple example groups. The method is passed a string identifier and a block where all the examples are declared. Later, the include_examples is invoked within the body of an example group and passed the string identifier. Multiple shared examples can be used; it is common to store these in a separate helper file that is imported by other spec files.

Preview 10:11

A complement to shared examples, the shared_context method allows for multiple example groups to rely on common boilerplate code. The developer can reduce duplication by declaring before blocks, instance variables, helper methods, and let variables  in a shared context. The include_context method is then used to inject that context into multiple example groups.

Shared Context with include_context
07:34
Test your knowledge of the refactoring techniques introduced in this section.
Subjects, Shared Examples, and Shared Context
5 questions
+ Built-In Matchers
17 lectures 02:01:00

This section is focused on the matchers available in RSpec. A matcher is a type of assertion, expectation or validation. RSpec includes a variety of matchers -- everything from equality to inclusion to identity to error raising. The not_to method is an alternative to the to method that checks for the inverse or negative of a given matcher. For example, not_to eq will check for inequality.

The not_to Method
04:38

The eq matcher checks only for value equality. The stricter eql matcher checks for both value and data type. For example, eq would consider the integer value 3 and the floating point value 3.0 to be equal. eql would not consider the two equal because they are of different data types.

Equality Matchers I (eq and eql)
05:30

The equal matcher checks that two values are identical. To be identical, the values must both be the same object in the computer's memory. Identity is the strictest form of equality. In this lesson, we apply these matchers to arrays and introduce a real-life analogy of houses in a neighborhood.

Equality Matchers II (equal and be)
09:50

RSpec includes support for numerical comparisons like greater than and less than or equal to. Use the be matcher followed by the proper Ruby operator. For example, expect(10).to be >= 5 will pass if 10 is found to be greater than or equal to 5.

Preview 06:03
Equality and Comparison Matchers
6 questions

A predicate method is one that returns a Boolean value -- either a true or a false. RSpec includes dynamic matchers for testing predicate methods. For any method, remove the question mark from the name and prefix it with be_. For example, the empty? method on an array can be tested with the predicate matcher be_empty.

Predicate Matchers
07:45

The all matcher performs an aggregate check --- it validates that all elements in array fit some criteria. For example, expect([2, 4, 6]).to all(be_even) asserts that each value in an array is even. The matcher can also accept a mathematical comparison like be < 100 or be >= -2.

all Matcher
06:20

Ruby has two falsy values: false and nil. All other objects are considered truthy, which means that they evaluate to true in a conditional context. In this lesson, we introduce the be_truthy and be_falsy matchers for asserting truthiness / falsiness as well as the be_nil matcher for explicit comparisons to nil.

be Matcher (Truthy, Falsy and Nil Values)
07:23
Test your knowledge of the concepts introduced in the previous lessons.
Predicate, all and be Matchers
4 questions

One of the most powerful matchers in RSpec, the change matcher compares the value of something before and after an operation. Pass the expect method a block with some code that may mutate an object's state. Afterwards, invoke the change matcher with another block that describes what value is being tracked. Several comparison methods are available: the from / to combo as well as by.

change Matcher
10:02

The contain_exactly matcher asserts that a sequence of elements is found within a collection, irrespective of order. The method is passed a comma-separated list of arguments to search for. If order matters, a more equality-focused matcher like eq would be used.

contain_exactly Matcher
04:06

The start_with and end_with matchers check for the presence of a smaller subset of elements at the beginning or end of a data structure. For a string, the matchers will check for a substring of characters. For an array, the matchers will check for the presence of elements in sequential order.

start_with and end_with Matchers
06:00

The have_attributes matcher confirms that an object has a set of attributes with corresponding values. The method accepts a hash where the key is the name of the attribute and the value is the corresponding attribute value. When testing a custom object, the attributes have to be publicly accessible via reader methods to be able to be checked.

have_attributes Matcher
04:35

The include matcher checks for the inclusion of an object within a larger object. It can be used to check for a substring within a string, a value within an array, a key within a hash, and even a key-value pair within a hash. This matcher is not concerned with order, only with presence.

include Matcher
06:16

The raise_error matcher checks that a block of code triggers an error. It is recommend to pass the matcher a specific error to watch out for. Otherwise, it becomes difficult to ascertain whether the expected error was the one that caused the spec to pass.

raise_error Matcher
09:11

The respond_to matcher verifies that an object can receive one or more given methods. The implementation and return values of the methods is not considered; this matcher checks only that the object has a method defined on its public interface. The additional with method confirms that the method is called with a specific number of arguments.

respond_to Matcher
09:01

The satisfy matcher is used to define custom assertions. This offers the best opportunity for defining expectations that tie in to the business logic of your app. In this lesson, we use satisfy to check if a string is a palindrome.

satisfy Matcher
09:42

The not_to method tests for the negative or inverse of any RSpec matcher. For example, not_to include affirms that an array does not include a value. In this lesson, we practice the syntax while reviewing many of the matchers introduced in this section.

not_to Method
08:21

Compound expectations can chain together two or more expectations. The and method ensures both of the matchers pass while the or method ensures either of the matchers pass. In this lesson, we explore the syntax in the context of a randomness problem.

Compound Expectations
06:17
Test your knowledge of compound expectations by writing some specs.
Compound Expectations
3 questions
+ Mocks
10 lectures 01:51:40

A double is a stand-in for a real object in a test. Doubles allow us to isolate specs to test app components (such as classes) independently. In this lesson, we create a sample stuntman double and walk through the syntax to permit and receive methods on it.

Create a Test Double
15:37
A double is a mock object that stands in for a real object in a test suite. Test your knowledge of creating doubles and assigning them methods in this assignment.
Doubles
2 questions

In this lesson, we do some light prep work to set up the upcoming tests. All examples are tied to the real-life situation of a movie set with real actors and stunt doubles.

Set up Our Test Movie
08:44

In this lesson, we replace our real object with a test double, connecting the ideas introduced in the last two lessons. The allow method defines a mock method on a double and the expect method affirms that it is called.

Replacing an Object with a Double
12:32

In this lesson, we introduce new methods like at_most, at_least, once, and exactly to test how many times a method was received on a double. The method counts are not independent between different assertions so these methods cannot be stacked.

Receive Counts
07:26

The allow method is incredibly versatile -- it can be customized to respond to different arguments as well as return different return values. In this lesson, we use the method to create a double that mocks the functionality of a Ruby array.

The allow Method
11:48

A method stub’s return value can be customized depending on the number or arguments, the type of arguments, or specific argument values. The ​with​ method specifies the number of expected arguments. In this lesson, we continue exploring how we can modify the allow method.

Matching Arguments
10:33

Verifying doubles are stricter alternatives to normal doubles. RSpec checks that the methods being stubbed are present on the underlying object. The ​instance_double​ method takes a class name or object as its argument. It verifies any method being stubbed would be present on an instance of that class.

Instance Doubles
13:37

Class doubles mock a class and its class methods rather than its instance methods. One advantage of ​the class_double​ method is that the class itself have to be defined -- this allows for test-driven development.

Class Doubles
13:23

Spies are an alternate type of test double. They spy / observe the behavior of an object and all of the methods it receives. Spies follow a different pattern than a double -- they assert a message has been received after an action.

Spies I
08:16

In this lesson, we practice using spies with a Garage / Car class combo.

Spies II
09:44
+ Conclusion
1 lecture 01:05

Congratulations on making it to the end of the course! I hope the course has been as fun to watch as it was for me to produce. Best of luck in all of your coding endeavors!

Conclusion
01:05
Requirements
  • Intermediate knowledge of the Ruby programming language (classes, objects, data structures, etc)
  • Modern version of Ruby (>2.4)
  • Text editor (VSCode is recommended)
Description

Welcome to Testing Ruby with RSpec: The Complete Guide!

This course offers a comprehensive overview of the RSpec testing library for the Ruby programming library. RSpec is the most popular Ruby Gem of all time, with over 300 million downloads to date.

If you're new to the topic, testing is the practice of "writing code that confirms that other code works as expected". Tests control for regressions, which are changes to the code that break the program.

The benefits of testing extend outside of the codebase. Adopting a test-driven approach will also make you a better developer. Tests force you to think critically about the program and its features: the classes, the objects, the methods and more.

Testing Ruby with RSpec begins with the essentials and proceeds to more complex topics including:

  • Installation

  • Project Initialization

  • Test-Driven Development (TDD)

  • let variables

  • before and after Hooks

  • Subjects

  • Shared Examples

  • Shared Context

  • Built-in Matchers

  • Mocks and Doubles

  • Instance Doubles

  • Class Doubles

As a software engineer and consultant who's worked with Ruby for several years, I'm excited to introduce you to the awesome RSpec library, its elegant syntax, and all of its fun quirks.

Thanks for checking out the course!

Who this course is for:
  • Intermediate Ruby developers interested in upgrading their skill set
  • Programmers who want to explore the fundamentals of testing and TDD