Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Rspec Essentials
Rspec Essentials

Rspec Essentials: Develop testable, modular, and maintainable Ruby software for the real world using RSpec

eBook
$32.39 $35.99
Paperback
$43.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Rspec Essentials

Chapter 1. Exploring Testability from Unit Tests to Behavior-Driven Development

In this book, we are going to learn about RSpec in depth. But first, we need to lay some foundations. This chapter will introduce some important information that will prepare us for our exploration of RSpec.

First, we'll discuss the exciting promise of automated tests. We'll also discuss some of the pitfalls and challenges that are common when writing tests for real-world apps.

Next, we'll introduce the concept of testability, which will stay with us throughout this book. We'll then go over the technical assumptions made in the book.

We'll then start writing some simple unit tests with RSpec and explore the basic concepts of unit and test. We'll also start thinking about the usefulness of our tests and compare the cost of testing with its benefits.

Finally, we'll learn about two popular software methodologies: test-driven development (TDD) and behavior-driven development (BDD).

The promise of testing

When I first learned about automated tests for software, it felt as if a door to a new world had opened up. Automated tests offered the promise of scientific precision and engineering rigor in software development, a process which I thought was limited by its nature to guesswork and trial and error.

This initial euphoria lasted less than a year. The practical experience of creating and maintaining tests for real-world applications gave me many reasons to doubt the promise of automated tests. Tests took a lot of effort to write and update. They often failed even though the code worked. Or the tests passed even when the code did not work. In either scenario, much effort was devoted to testing, without much benefit.

As the number of tests grew, they took longer and longer to run. To make them run faster, more effort had to be devoted to optimizing their performance or developing fancy ways of running them (on multiple cores or in the cloud, for example).

But even with many, many tests and more lines of test code than actual application code, many important features had no tests. This was rarely due to negligence but due to the difficulty of testing many aspects of real-world software.

Finally, bugs still popped up and tests were often written as part of the bug fix to ensure these bugs would not happen again. Just as generals always prepare for the last war, tests were ensuring the last bug didn't happen without helping prevent the next bug.

After several years of facing these challenges, and addressing them with various strategies, I realized that, for most developers, automated tests had become a dogma, and tests were primarily written for their own sake.

To benefit from automated tests, I believe one must consider the cost of testing. In other words, the effort of writing the test must be worth the benefits it offers. What I have learned is that the benefit of tests is rarely to directly prevent bugs, but rather to contribute to improved code quality and organization, which, in turn, will lead to more reliable software. Put another way, although automated tests are closely tied to quality assurance, their focus should be on quality, not assurance. This is just common sense if you think about it. How can we give assurance with automated (or manual) tests that a real-world piece of software, composed of thousands of lines of code, will not have bugs? How can we predict every possible use case, and how every line of code will behave?

Another issue is how to write tests. A number of challenges arise when testing complex applications in the real world. Should you use fixtures or mocks to test models? How should you deal with rack middleware in controller tests? How should you test code that interacts with external APIs and services? This book offers the essentials required to solve problems like these with RSpec, the popular Ruby testing library.

The goal of this book is to help you effectively leverage RSpec's many features to test and improve your code. Although we will limit ourselves to the most pertinent options, I encourage you to consult the official RSpec documentation (http://rspec.info/documentation/) to learn more about all the possible options. You should find it easy to build upon the examples here to develop a custom solution that exactly meets your own needs and preferences.

Testability

A fundamental concept that unites the chapters of this book is testability. When code is testable, we have confidence in its architecture and implementation. We can test it thoroughly with ease. Bugs are quickly detected and easily fixed. The first step to improving testability in an application is to establish a natural feedback loop between application code and test code, using signals from testing to improve application code. The energy devoted to writing complex tests for untestable code should be channeled into making the code more testable, allowing simpler tests to be written. With this feedback loop and focus on testability, tests contribute to code quality and application reliability.

Testability is not a binary quality. When looking at a given software system, we should ask, "How testable is this?", rather than trying to categorize it as testable or not testable. This requires judgment and common sense. As our features and priorities evolve, so must our criteria for testability. For example, let's consider a new web application with a small number of users, which has all kinds of automated tests for important features but none for testing performance under high load. This system can be considered to have high testability as long as we have few users and performance is not yet a concern. Once the web application becomes very popular and we need to serve millions of requests a day, we would have to change our judgment to say that the system now has very low testability. What use are all the tests that aren't related to performance if none of our users can reach our website because we cannot serve requests fast enough?

Testability should be achieved with efficiency. We need to figure out which features to test and not spend too much effort on tests that don't offer much value. As with testability, efficiency is not static and we must adjust the criteria for it as software evolves.

We can define testability as the degree to which a system can be verified to work as expected. At the smallest level, closest to the individual lines of code that make up our software, we are concerned with whether functions return the values we expect. At higher levels of abstraction, we are concerned with behaviors such as error handling, performance, and the correctness of entire end-to-end features. Let's keep in mind that testability includes manual tests as well. Manual testing is a normal part of development and quality assurance. If an aspect of a software system cannot be tested manually, it is very likely that it will be quite difficult to test it using automated tools as well.

Often, developers struggle to automate manual tests for a system with low testability. This common pitfall leads to high-cost, low-value tests and a system whose architecture and organization is not improved by the testing efforts. Our focus in this book will be on improving testability using automated tests written with RSpec. We will make both manual and automated tests better, with less effort required to create and maintain our tests. Both the architecture and organization of our system will benefit. By diverting some of our testing energy to improving the testability of the code, we will be engaged in a positive feedback loop, whereby our effort devoted to testing provides a meaningful benefit without excessive cost.

Technical assumptions

This book assumes that the reader is comfortable reading and writing Ruby code. Familiarity with RSpec is strongly recommended, though a total beginner to RSpec should find it possible to understand most of the recipes with the help of the online RSpec documentation. Each code example has been tested and works. I have used the latest stable versions available at the time of writing: Ruby 2.3.0 with RSpec 3.4.0.

RSpec 3 uses a different syntax from RSpec 2. Version 2.13 introduced a new syntax for assertions while 2.14 introduced a new syntax for doubles and expectations. RSpec 3.0 introduced a number of new features and changes as well. I have used the new syntax and features throughout the book:

require 'rspec'

describe 'new RSpec syntax' do
  it "uses the new assertion syntax" do
    # new                           # deprecated
    expect(1 + 1).to eq(2)          # (1 + 1).should == 2
  end

  context "mocks and expectations" do
    let(:obj) do
      # new                          # deprecated
      double('foo')                  # obj = mock('foo')      
    end
    
    it "uses the new allow syntax for mocks" do
      # new                          # deprecated
      allow(obj).to receive(:bar)    # obj.stub(:bar)
    end

    it "uses the new expect syntax for expectations" do
      # new                          # deprecated
      expect(obj).to receive(:baz)   # obj.should_receive(:baz)
      
      obj.baz
    end    
  end
end

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:

Running our first spec

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:

Running our first spec

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:

Running our first spec

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!

Understanding the unit test

What is a unit of code? A unit is an isolated collection of code. A unit can be tested without loading or running the entire application. Usually, it is just a function. It is easy to determine what a unit is when dealing with code that is well organized into discrete and encapsulated modules. On the other hand, when code is splintered into ill-defined chunks that have cross-dependencies, it is difficult to isolate a logical unit.

What is a test? A test is code whose purpose is to verify other code. A single test case, (often referred to as an example in the RSpec community) consists of a set of inputs, one or more function calls, and an assertion about the expected output. A test case either passes or fails.

What is a unit test? It is an assertion about a unit of code that can be verified deterministically. There is an interdependency between the unit and the test, just as there is an interdependency between application code and test code. Finding the right unit and writing the right test go hand in hand, just as writing good application code and writing good test code go hand in hand. All of these activities occur as part of the same process, often at the same time.

Let's take the example of a simple piece of code that validates addresses. We could embed this code inside a User model that manages a record in a database for a user, like so:

Class User

  ...
  
  def save
    if self.address.street =~ VALID_STREET_ADDRESS_REGEX &&
       self.address.postal_code =~ VALID_POSTAL_CODE_REGEX &&
       CITIES.include?(self.address.city) &&
       REGIONS.include?(self.address.region) &&
       COUNTRIES.include?(self.address.country)
       
       DB_CONNECTION.write(self)
       
       true
     else
       raise InvalidRecord.new("Invalid address!")
     end
    end
   
   ...
   
  end

Writing unit tests for the preceding code would be a challenge, because the code is not modular. The separate concern of validating the address is intertwined with the concern of persisting the record to the database. We don't have a separate way to only test the address validation part of the code, so our tests would have to connect to a database and manage a record, or mock the database connection. We would also find it very difficult to test for different kinds of error, since the code does not report the exact validation error.

In this case, writing a test case for the single User#save method is difficult. We need to refactor it into several different functions. Some of these can then be grouped together into a separate module with its own tests. Finally, we will arrive at a set of discrete, logical units of code, with clear, simple tests.

So what would a good unit look like? Let's look at an improved version of the User#save method:

Class User


  def valid_address?
    self.address.street =~ VALID_STREET_ADDRESS_REGEX      &&
      self.address.postal_code =~ VALID_POSTAL_CODE_REGEX  &&
      CITIES.include?(self.address.city)                   &&
      REGIONS.include?(self.address.region)                &&
      COUNTRIES.include?(self.address.country)
  end

  def persist_to_db
    DB_CONNECTION.write(self)
  end

  def save
    if valid_address?
      persist_to_db 
      true
    else
      false
    end
  end

  def save!
    self.save || raise InvalidRecord.new("Invalid address!")    
  rescue
    raise FailedToSave.new("Error saving address: #{$!.inspect}")
  end

...

end

Therefore, we write unit tests for two distinct reasons: first, to automatically test our code for correct behavior, and second, to guide the organization of our code into logical units.

Automated testing has evolved to include many categories of tests (for example, functional, integration, request, acceptance, and end-to-end). Sophisticated development methodologies have also emerged that are premised on automated verification, the most popular of which are TDD and BDD. The foundation for all of this is still the simple unit test. Code with good unit tests is good code that works. You can build on such a foundation with more complex tests. You can base your development workflow on such a foundation.

However, you are unlikely to get much benefit from complex tests or sophisticated development methodologies if you don't build on a foundation of good unit tests. Further, the same factors that contribute to good unit tests also contribute, at a higher level of abstraction, to good complex tests. Whether we are testing a single function or a complex system composed of separate services, the fundamental questions are the same. Is the assertion clear and verifiable? Is the test case logically coherent? Are the inputs and outputs precisely specified? Are error cases considered? Is the test readable and maintainable? Does the test often provide false positives (the test passes even though the system does not behave correctly) or false negatives (the test fails even though the system works correctly)? Is the test providing value, or is it more trouble than it's worth?

In summary, testing begins and ends with the unit test.

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:

Writing specs with RSpec

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.

Test-driven development

It seems to make sense to write your code first and then to test it, as we did in our AddressValidator example above. Many people follow this approach. However, many others follow a process called TDD, where the tests are written first. Why do this? Let's take a brief aside before answering the question.

If you look at RSpec's official documentation, you will find that instead of the word test, the word example is used to describe the individual assertions to be found within the it block. Although it may appear less natural than test, in some ways example is more accurate. Automated tests rarely provide conclusive proof that a software system, or even just one of its functions, works. Most often, they contain a few test cases, which are nothing but examples of the code in action. Moreover, one of the main benefits of an automated assertion is to document the way the code behaves. Whereas test suggests a proof of correctness, example just suggests an instance of the code in action.

Coming back to the question of why someone would write their test before their code, we can apply the concept of the example. A methodical software engineer could benefit from documenting the code about to be written with some examples. Rather than adding these as comments in the code, the documentation can be written in the form of automated tests, or assertions. This way, as the code is being written, the tests can be run to give some feedback about how close, or how far, the code is to performing as initially expected.

If we refer to RSpec's home page, there is a link provided (https://relishapp.com/rspec), where we can read the following description:

RSpec is a Behaviour-Driven Development tool for Ruby programmers. BDD is an approach to software development that combines Test-Driven Development, Domain Driven Design, and Acceptance Test-Driven Planning. RSpec helps you do the TDD part of that equation, focusing on the documentation and design aspects of TDD.

We see that TDD is mentioned, but the first sentence identifies RSpec with BDD. Although a definition is given, it refers to three other methodologies, leaving us perhaps with only a vague impression of some fancy approach to software development. So what is BDD really?

Behavior-driven development

BDD is an extension of the concepts of TDD to the complete functioning of a software system. Indeed, according to some proponents, BDD is a method for operating an entire organization!

Whereas TDD is concerned with tests and code, BDD is concerned with behaviors and benefits. BDD attempts to express the behavior of a system in plain, human language and justify the benefits that the behavior provides. TDD is written in code and does not attempt to justify the value of any part of the system. The loftiest vision of BDD is a methodology by which all features are specified and justified in clear human language, which can automatically be executed to verify that the system works as expected. Some other names sometimes used to refer to this lofty vision of BDD are Specification by Example and executable documentation.

If we look at our AddressValidator example, mentioned previously, we have an example of TDD. If we were to create a BDD-oriented specification for it, we may start with something like this:

Feature: Address Validation
  As a postal customer,
  In order to ensure my packages are delivered,
  I want to validate addresses

Scenario: Invalid address
  Given I enter "Seoul, USA"
  When I validate the address
  I should see the error message, "City and Country do not match"

This is the beginning of a Cucumber example. We won't go into Cucumber any further in this book, but it should be noted that RSpec is a closely related tool, and many of the developers who contribute to RSpec also contribute to Cucumber.

In the real world, the dividing line between TDD and BDD is not that clear. For most practical purposes, the only difference between TDD and BDD is in the style of the syntax used for expressions.

TDD leans more toward programmatic syntax, such as:

assert_equal(x, 5)

BDD, however, would use a syntax closer to human language, like RSpec's:

expect(x).to eq(5)

For the purposes of this book, we will strike a practical balance between TDD and BDD. Just by using RSpec, we are getting a hefty dose of BDD in our syntax. But we can still choose to structure our tests to follow the structure of our code (for example, having a single test for every function), which are nothing but unit tests. We can also choose to structure our tests according to high-level features, which is closer to BDD, or integration tests. In fact, we need to do a bit of both of these kinds of tests, as well as some tests that fall in between, which are sometimes called functional tests.

Summary

In this chapter, we have introduced the potential benefits and costs of automated testing, with a focus on the concept of testability, which we defined as the degree to which a system can be verified to work as expected. We learned about the importance of maintaining a positive balance between the benefits of testing and the cost of creating and maintaining tests. We then wrote a couple of simple unit tests and ran them with RSpec. Finally, we looked at different approaches to automated testing, from unit tests to TDD and BDD.

Left arrow icon Right arrow icon

Key benefits

  • Explore the concept of testability and how to implement tests that deliver the most value
  • Maximize the quality of your Ruby code through a wide variety of tests
  • Master the real-world tradeoffs of testing through detailed examples supported by in-depth discussion

Description

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.

Who is this book for?

This book is aimed at the software engineer who wants to make their code more reliable and their development process easier. It is also aimed at test engineers who need to automate the testing of complex systems. Knowledge of Ruby is helpful, but even someone new to the language should find it easy to follow the code and tests.

What you will learn

  • * Identify a unit of software for the purposes
  • of testing
  • * Manage test states with hooks, fixtures,
  • and mocks
  • * Handle external web services in tests
  • using various techniques
  • * Configure RSpec flexibly and cleanly using
  • support code and environment variables
  • * Interact with rich web apps in tests
  • using Capybara
  • * Build the right feature with behavior-driven
  • development
  • * Customize matchers and failure messages
  • * Verify correct development and production
  • environments
Estimated delivery fee Deliver to United States

Economy delivery 10 - 13 business days

Free $6.95

Premium delivery 6 - 9 business days

$21.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Apr 21, 2016
Length: 222 pages
Edition : 1st
Language : English
ISBN-13 : 9781784395902
Category :
Languages :

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to United States

Economy delivery 10 - 13 business days

Free $6.95

Premium delivery 6 - 9 business days

$21.95
(Includes tracking information)

Product Details

Publication date : Apr 21, 2016
Length: 222 pages
Edition : 1st
Language : English
ISBN-13 : 9781784395902
Category :
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 87.98
Comprehensive Ruby Programming
$43.99
Rspec Essentials
$43.99
Total $ 87.98 Stars icon

Table of Contents

11 Chapters
1. Exploring Testability from Unit Tests to Behavior-Driven Development Chevron down icon Chevron up icon
2. Specifying Behavior with Examples and Matchers Chevron down icon Chevron up icon
3. Taking Control of State with Doubles and Hooks Chevron down icon Chevron up icon
4. Setting Up and Cleaning Up Chevron down icon Chevron up icon
5. Simulating External Services Chevron down icon Chevron up icon
6. Driving a Web Browser with Capybara Chevron down icon Chevron up icon
7. Building an App from the Outside In with Behavior-Driven Development Chevron down icon Chevron up icon
8. Tackling the Challenges of End-to-end Testing Chevron down icon Chevron up icon
9. Configurability Chevron down icon Chevron up icon
10. Odds and Ends Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.3
(3 Ratings)
5 star 33.3%
4 star 0%
3 star 33.3%
2 star 33.3%
1 star 0%
J S Apr 28, 2016
Full star icon Full star icon Full star icon Full star icon Full star icon 5
As one of the technical editors on this project, I can say this is a great book for people who already know some ruby and would like to dive into testing with RSpec. It covers all aspects of testing including mocking external services, integration tests with capybara, selenium and complete end-to-end examples. It covers some of the tricky parts of testing like testing time, testing mixins, and how to find false positives. Some of these things you only learn by experience and you can learn on the experience of this author to advance your RSpec skills quickly.
Amazon Verified review Amazon
Jeff Nyman Aug 14, 2016
Full star icon Full star icon Full star icon Empty star icon Empty star icon 3
I'm very torn on this book. I think the author has a good writing style and means of presentation. I like how the examples in the book are built up and how the explanations around those examples provide an incremental increase in context. The conversational tone of the book is also very welcome, as I believe it lends itself well to this kind of subject.However, all that being said, this book is plagued by what plagues many other Packt books: poor quality of the examples. Going through Chapter 2 alone, for example, you will find many mistakes not just in the text, but in the code as well.For the text problems, the issue seems to be that code was changed after the text was written but the text was not changed to reflect that. Ironic in a book that is ultimately about testing: you always make sure to test the final product.For the code, the issue is that some of it simply doesn't work as it is provided. Further, if you look at the code download that Packt makes available for the site, you will often find that the code there differs from what is in the book. And sometimes both of those differ from what the text itself describes.There is apparently one of the "technical editors" who wrote a review for this book. I'm not sure I would necessarily admit to that, given some of these issues. (Technical editors are responsible for technical accuracy.) As one of the more obvious lacks of accuracy -- and you literally cannot miss it, there is an AddressValidator class created at one point. The book itself has you call an invalid_parts() method as part of the RSpec tests for that class. Yet the AddressValidator class shown in the book has no invalid_parts() method. Nor -- at the time of writing this review -- did the code download from the Packt site. This is but one of many other issues.This happens just enough that -- depending on your time, patience, and tolerance -- you run up against a trust barrier. This is the killer problem for technical books. If readers start to feel they can't trust what the book is showing them, they are likely to go somewhere else for the information. Most likely to the numerous blogs that document tools like RSpec and can be updated on the fly if errors are found.I do want to stress that, depending on your overall experience and skill level, you absolutely can get useful information out of this book, which is why I rate this book with three stars. But there can be a lot of overhead to getting that useful information. It really is up to each reader whether the overhead is worth the effort. The best a reviewer like myself can do is at least provide you with the cautionary aspect.RSpec is a fantastic tool and Ruby is a fantastic language. It pains me to see what should be a excellent resource like this not pass muster. There is no way, for example, that I could recommend this book to any company I do consulting for. Even though I really, really want to.
Amazon Verified review Amazon
Beverly Jul 26, 2016
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
I've been going through the book, doing the examples on each page. I'm currently on page 57, and I've found 5 errors that make the examples incorrect. Unless you correct the syntax errors and add missing methods to the example classes, you won't be able to follow the examples. So far, I also haven't seen good organization of thoughts. Lots of examples, and many of them don't work.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the digital copy I get with my Print order? Chevron down icon Chevron up icon

When you buy any Print edition of our Books, you can redeem (for free) the eBook edition of the Print Book you’ve purchased. This gives you instant access to your book when you make an order via PDF, EPUB or our online Reader experience.

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
Modal Close icon
Modal Close icon