34,79 €
Develop testable, modular, and maintainable Ruby software for the real world using RSpec
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.
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.
This comprehensive tutorial is packed with real-world examples of testing with RSpec. The most important features of RSpec are introduced in the early chapters and are used in examples of growing complexity in the following chapters. Concepts and methodologies are discussed in detail.
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 233
Veröffentlichungsjahr: 2016
Copyright © 2016 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
First published: April 2016
Production reference: 1130416
Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham B3 2PB, UK.
ISBN 978-1-78439-590-2
www.packtpub.com
Author
Mani Tadayon
Reviewers
Stefan Daschek
Nola Stowe
Commissioning Editor
Amarabha Banerjee
Acquisition Editor
Reshma Raman
Content Development Editor
Rashmi Suvarna
Technical Editor
Anushree Arun Tendulkar
Copy Editor
Safis Editing
Project Coordinator
Judie Jose
Proofreader
Safis Editing
Indexer
Rekha Nair
Graphics
Abhinash Sahu
Production Coordinator
Manu Joseph
Cover Work
Manu Joseph
Mani Tadayon first learned to program as a shy 7th grader on an Apple IIe using BASIC. He went on to learn Pascal, C++, Java, JavaScript, Visual Basic, and PHP before becoming a Ruby developer in 2008. With 15 years of experience in the software industry, he has developed expertise in web development, infrastructure, and testing. Mani's interests and education are broad, with degrees in foreign languages, computer science, and geography. He lives just far enough from Silicon Valley with his family and their many, many Shiba Inus.
Stefan Daschek started hacking on computers back in the days of the Commodore 64/128. Since then, he has studied computer sciences at TU Vienna and founded his own company, Büro DIE ANTWORT. Currently, he is mainly developing and maintaining complex web applications written in Ruby on Rails, and sometimes soldering stuff and building small robots. His original Commodore 128 is still working and used for a collective session of Summer Games every so often.
Nola Stowe has been programming with Ruby since Rails 0.8 and testing with RSpec since its early days. She is an independent consultant, helping to augment teams of Ruby and Clojure developers. She has also been a technical reviewer for Instant RSpec Test-Driven Development, Packt Publishing and The Rails Way, First Edition. Nola blogs at http://blog.rubygeek.com and http://www.clojuregeek.com.
Thanks to my husband Nick for doing the mundane things in life to allow me time do what I love doing. You are the greatest!
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at <[email protected]> for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks.
https://www2.packtpub.com/books/subscription/packtlib
Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book library. Here, you can search, access, and read Packt's entire library of books.
RSpec is one of the reasons why the Ruby programming language has become so popular. There is a strong emphasis on testing, documentation, and iterative development in the Ruby community. With RSpec, it is easy to create excellent tests that specify behavior and improve the development process.
In this book, we'll learn how to use RSpec in a real-world setting. We'll also learn about the concept of testability, which relates to our application code as well as to our tests. Throughout, we'll focus on writing tests that are valuable and stay away from testing for its own sake.
RSpec offers a variety of tools for creating test scenarios, assertions, and error messages. We can create the tests we need and get the exact output we want using RSpec without having to do too much work. RSpec has been under development for almost 10 years, so it has evolved significantly. Many ways of writing tests have developed due to the flexibility of RSpec and the underlying Ruby language. Some of these are clever but some others are too clever. We'll learn about a solid subset of RSpec's features that are reliable and avoid some of the trickier features.
Today, professional software development must include automated testing. However, testing presents many challenges in the real world. There is a danger of learning about testing tools without knowing how to use them effectively. In this book, we will always keep an eye on the real world, even in our simple examples. We'll cover a range of application types, from libraries to rich web UIs, and a range of approaches to testing, from unit tests to behavior-driven development. Along the way, we'll discuss potential pitfalls and develop production-grade solutions to avoid them.
As you progress through this book, you will learn about many RSpec features, my recommended approach to using them, and their relation to testability. I hope that you can use this book both as a handbook for simple tasks and as a guide to developing a sophisticated understanding of automated software testing.
Chapter 1, Exploring Testability from Unit Tests to Behavior-Driven Development, defines the basic concepts of unit, test, and testability, and puts them in context.
Chapter 2, Specifying Behavior with Examples and Matchers, shows how RSpec's basic features implement units and assertions.
Chapter 3, Taking Control of State with Doubles and Hooks, discusses how RSpec implements mocks and hooks to allow us to set up a test scenario.
Chapter 4, Setting Up and Cleaning Up, delves further into how we can simulate external resources such as databases and web servers while keeping our test environment clean using RSpec support code.
Chapter 5, Simulating External Services, extends our discussion of handling external web services by using the VCR gem.
Chapter 6, Driving a Web Browser with Capybara, introduces the Capybara library, and shows how to use it to test rich web UIs.
Chapter 7, Building an App from the Outside In with Behavior-Driven Development, explains BDD and how RSpec can be used to define high-level features.
Chapter 8, Tackling the Challenges of End-to-end Testing, continues with the development of the app built in the previous chapter, focusing on common testing pain points, such as authentication.
Chapter 9, Configurability, introduces a concept that is related to testability and an implementation of a real-world configuration system.
Chapter 10, Odds and Ends, wraps up the book by covering a few advanced topics that didn't quite fit into the previous chapters, but which were too important to leave out.
You'll need two basic pieces of software for this book: Ruby and RSpec.
You can install the Ruby programming language from its web site:
https://www.ruby-lang.org/en/downloads/
The latest version at the time of writing is 2.3.0. Any version of Ruby greater than 2.0 should be fine.
I recommend that you use rbenv to install Ruby. This tool will make it easier to keep a clean Ruby environment. Professional Ruby developers rely on rbenv or similar tools to install and manage Ruby on their systems. You can find more info on rbenv on its GitHub page:
https://github.com/rbenv/rbenv
You can install RSpec using the rubygems installer (gem install rspec). The latest version of RSpec at the time of writing is 3.4.0, but any version greater than 3.0 should work fine. More details on RSpec can be found on its GitHub repo:
https://github.com/rspec/rspec
This book is for the programmer who has some experience with Ruby. If you have written some small programs and are familiar with defining basic functions, modules, and classes, then you should be fine. If you have no background in Ruby, you will still be able to follow along, but will need to do a little extra work to follow the more complicated sections. I've done my best to build up complex examples step by step and clearly explain every aspect of the code samples with comments.
Feedback from our readers is always welcome. Let us know what you think about this book—what you liked or disliked. Reader feedback is important for us as it helps us develop titles that you will really get the most out of.
To send us general feedback, simply e-mail <[email protected]>, and mention the book's title in the subject of your message.
If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide at www.packtpub.com/authors.
Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase.
You can download the example code files for this book from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
You can download the code files by following these steps:
You can also download the code files by clicking on the Code Files button on the book's webpage at the Packt Publishing website. This page can be accessed by entering the book's name in the Search box. Please note that you need to be logged in to your Packt account.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
We also provide you with a PDF file that has color images of the screenshots/diagrams used in this book. The color images will help you better understand the changes in the output. You can download this file from http://www.packtpub.com/sites/default/files/downloads/RSpecEssentials_ColoredImages.pdf.
Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in the text or the code—we would be grateful if you could report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded to our website or added to any list of existing errata under the Errata section of that title.
To view the previously submitted errata, go to https://www.packtpub.com/books/content/support and enter the name of the book in the search field. The required information will appear under the Errata section.
Piracy of copyrighted material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy.
Please contact us at <[email protected]> with a link to the suspected pirated material.
We appreciate your help in protecting our authors and our ability to bring you valuable content.
If you have a problem with any aspect of this book, you can contact us at <[email protected]>, and we will do our best to address the problem.
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).
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.
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.
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:
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:
Then we'll run the rspec command on it:
