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

Running our first spec


Let's get started writing our first RSpec spec file before we delve deeper into the concepts of the unit and the assertion. First, let's try an empty file. What will happen if we create an empty file called empty.rb and try to run it as an RSpec spec file? On a POSIX (Portable Operating System Interface) based operating system, such as Linux or OS X, we could do the following:

We can see that RSpec correctly reports that there are no examples in the file. However, we also notice that RSpec reports that there are zero failures, which is, strictly speaking, correct. Finally, the last line shows the exit status of the rspec empty.rb command. An exit status of zero (0) indicates success on POSIX systems, which means that our empty test succeeded.

This seems a bit odd. There isn't a bug in RSpec, and we haven't made any typos. It's important to keep this simplest of cases in the back of our minds, even as we start building very complex specs. This empty test is useless and doesn't serve any purpose.

Let's move on to an actual spec file now. We'll create a file called hello_world.rb and put the following content in it:

require 'rspec'

describe 'hello world' do
  it 'returns true' do
    expect('hello world').to eq('hello world')
  end
end

Before we run this, let's have a look at what's in the file. Let's start from the inside out. The expect method declares an assertion, which is then specified with the to method together with the eq method. There are a number of matchers in RSpec, the most common of which is eq, which matches equality. Going out one layer, we see the it method, which is how we declare an example in RSpec. Finally, the describe method allows us to group one or more examples. We need to have at least one describe block and we can nest them in case of multiple blocks.

Now we'll run the spec and see what we get back:

The spec passed again, and we see RSpec correctly detected that there was a single example in the file. The single dot on the first line of output looks odd when running a single spec, but it is a useful progress indicator when running a large number of specs, as there is one green dot for every passing spec and one red F for every failing test.

Now, let's add a failing spec to see what the output looks like. We'll create a new file called hello_and_bye.rb with the following content:

require 'rspec'

describe 'hello and bye' do
  it 'returns true' do
    expect('hello').to eq('hello')
  end

  it 'fails' do
    expect('bye').to eq('hello')
  end
end

Then we'll run the rspec command on it:

This time we see that RSpec reports the failure, along with an explanation. We also notice that the exit status is no longer 0, but 1, which indicates failure. Any automated tools, such as continuous integration servers, would rely on that exit status to decide if our tests passed or failed, then react accordingly.

Now that we've seen some very rudimentary examples, let's remind ourselves of that first spec, the empty file. Are either hello_world.rb or hello_and_bye.rb any better than the empty file? Like the empty file, neither of these small spec files tests anything. We haven't even loaded any of our own code to test. But we've had to spend some effort to write the specs and haven't gotten anything in return. What's worse is that hello_and_bye.rb is failing, so we have to put in a little effort to fix it if we want our test suite to pass. Is there a point to fixing that failure?

These questions may seem absurd. However, developers writing tests will face such problems all the time. The question is, should we even write a test? The answer is not clear. The empty file represents that situation when we skip writing a test. The other two files represent cases where we've written useless tests, and where we have to spend time fixing a useless test in order to keep our test suite passing.

As we delve into RSpec, we will write specs that are very complex. Nevertheless, the fundamental issue will be exactly the same one that we faced with the empty file, hello_world.rb, and hello_and_bye.rb. We have to write tests that are useful and avoid wasting energy on writing and maintaining tests that don't serve a good purpose. The situation will be more nuanced, a matter of degrees of usefulness. But, in short, we should always consider the option of not writing a test at all!