Thanks to visit codestin.com
Credit goes to www.packtpub.com

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
Test Driven Python Development
Test Driven Python Development

Test Driven Python Development: Develop high-quality and maintainable Python applications using the principles of test-driven development

Arrow left icon
Profile Icon Siddharta Govindaraj
Arrow right icon
$38.99 $43.99
Full star icon Full star icon Full star icon Full star icon Half star icon 4.4 (5 Ratings)
eBook Apr 2015 264 pages 1st Edition
eBook
$38.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Siddharta Govindaraj
Arrow right icon
$38.99 $43.99
Full star icon Full star icon Full star icon Full star icon Half star icon 4.4 (5 Ratings)
eBook Apr 2015 264 pages 1st Edition
eBook
$38.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$38.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
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
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

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

Test Driven Python Development

Chapter 2. Red-Green-Refactor – The TDD Cycle

In the previous chapter, we went through a small TDD cycle by creating a failing test and then making it pass. In this chapter, we are going to fill out the rest of the Stock class by writing more tests. In the process, we will dig deeper into the TDD cycle and the unittest module.

Tests are executable requirements

In the first test, we wrote a very simple test that checked whether a new Stock class has its price attribute initialized to None. We can now think about what requirement we want to implement next.

An observant reader might have caught on to the terminology used in the previous sentence, where I said that we can think about the requirement to implement next, instead of saying that we can think about the test to write next. Both statements are equivalent, because in TDD, tests are nothing but requirements. Each time we write a test and implement code to make it pass, what we actually do is make the code meet some requirement. Looking at it another way, tests are just executable requirement specifications. Requirement documentation often goes out of sync with what is actually implemented, but this is impossible with tests, because the moment they go out of sync, the test will fail.

In the previous chapter, we said that the Stock class will be used to hold...

Arrange-Act-Assert

Let us start with the first requirement. Here is the test:

    def test_stock_update(self):
        """An update should set the price on the stock object
        We will be using the `datetime` module for the timestamp
        """
        goog = Stock("GOOG")
        goog.update(datetime(2014, 2, 12), price=10)
        self.assertEqual(10, goog.price)

Here we call the update method (which doesn't exist yet) with the timestamp and price and then check that the price has been set correctly. We use the assertEqual method provided in the unittest.TestCase class to assert the value.

Since we are using the datetime module to set the timestamp, we will have to add the line from datetime import datetime to the top of the file before it will run.

This test follows the pattern of Arrange-Act-Assert.

  1. Arrange: Set up the context for the test. In this case, we create a Stock object. In other tests, it may involve creating multiple objects or...

Documenting our tests

When we run the tests, we get the following output:

.E
==================================================================
ERROR: test_stock_update (__main__.StockTest)
An update should set the price on the stock object
------------------------------------------------------------------
Traceback (most recent call last):
  File "stock_alerter\stock.py", line 22, in test_stock_update
    goog.update(datetime(2014, 2, 12), price=10)
AttributeError: 'Stock' object has no attribute 'update'

------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (errors=1)

The test fails as expected, but the interesting thing is that the first line of the docstring is printed out on the fourth line. This is useful because we get some more information on which case is failing. This shows a second way of documenting out tests by using the first line for a short summary, and the rest of the docstring for a more detailed explanation...

Testing for exceptions

Another requirement is that the price should not be negative. We would want to raise a ValueError if the price is negative. How would we check for this expectation in a test? Here is one way to do that:

    def test_negative_price_should_throw_ValueError(self):
        goog = Stock("GOOG")
        try:
            goog.update(datetime(2014, 2, 13), -1)
        except ValueError:
            return
        self.fail("ValueError was not raised")

In the preceding code, we call the update method with a negative price. This call is wrapped with a try...except block to catch ValueError. If the exception is raised correctly, then control goes into the except block where we return from the test. Since the test method returned successfully, it is marked as passing. If the exception is not raised, then the fail method gets called. This is another method provided by unittest.TestCase and raises a test failure exception when it is called. We can pass in a message...

Exploring assert methods

Now we have just one requirement for update remaining:

  • -Done- It should take a timestamp and price value and set it on the object
  • -Done- The price cannot be negative
  • After multiple updates, the object gives us the latest price

Let us take the remaining requirement. Here is the test:

    def test_stock_price_should_give_the_latest_price(self):
        goog = Stock("GOOG")
        goog.update(datetime(2014, 2, 12), price=10)
        goog.update(datetime(2014, 2, 13), price=8.4)
        self.assertAlmostEqual(8.4, goog.price, delta=0.0001)

What this test does is to simply call update twice, and when we ask for the price, provide us with the newer one. The interesting point about the test is that we use the assertAlmostEqual method here. This method is often used when checking equality with floating point numbers. Why don't we use plain old assertEqual? The reason is that due to the way floating points are stored, the result may not be exactly the number you...

Tests are executable requirements


In the first test, we wrote a very simple test that checked whether a new Stock class has its price attribute initialized to None. We can now think about what requirement we want to implement next.

An observant reader might have caught on to the terminology used in the previous sentence, where I said that we can think about the requirement to implement next, instead of saying that we can think about the test to write next. Both statements are equivalent, because in TDD, tests are nothing but requirements. Each time we write a test and implement code to make it pass, what we actually do is make the code meet some requirement. Looking at it another way, tests are just executable requirement specifications. Requirement documentation often goes out of sync with what is actually implemented, but this is impossible with tests, because the moment they go out of sync, the test will fail.

In the previous chapter, we said that the Stock class will be used to hold price...

Arrange-Act-Assert


Let us start with the first requirement. Here is the test:

    def test_stock_update(self):
        """An update should set the price on the stock object
        We will be using the `datetime` module for the timestamp
        """
        goog = Stock("GOOG")
        goog.update(datetime(2014, 2, 12), price=10)
        self.assertEqual(10, goog.price)

Here we call the update method (which doesn't exist yet) with the timestamp and price and then check that the price has been set correctly. We use the assertEqual method provided in the unittest.TestCase class to assert the value.

Since we are using the datetime module to set the timestamp, we will have to add the line from datetime import datetime to the top of the file before it will run.

This test follows the pattern of Arrange-Act-Assert.

  1. Arrange: Set up the context for the test. In this case, we create a Stock object. In other tests, it may involve creating multiple objects or hooking a few things together that will be required...

Documenting our tests


When we run the tests, we get the following output:

.E
==================================================================
ERROR: test_stock_update (__main__.StockTest)
An update should set the price on the stock object
------------------------------------------------------------------
Traceback (most recent call last):
  File "stock_alerter\stock.py", line 22, in test_stock_update
    goog.update(datetime(2014, 2, 12), price=10)
AttributeError: 'Stock' object has no attribute 'update'

------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (errors=1)

The test fails as expected, but the interesting thing is that the first line of the docstring is printed out on the fourth line. This is useful because we get some more information on which case is failing. This shows a second way of documenting out tests by using the first line for a short summary, and the rest of the docstring for a more detailed explanation. The detailed explanation...

Testing for exceptions


Another requirement is that the price should not be negative. We would want to raise a ValueError if the price is negative. How would we check for this expectation in a test? Here is one way to do that:

    def test_negative_price_should_throw_ValueError(self):
        goog = Stock("GOOG")
        try:
            goog.update(datetime(2014, 2, 13), -1)
        except ValueError:
            return
        self.fail("ValueError was not raised")

In the preceding code, we call the update method with a negative price. This call is wrapped with a try...except block to catch ValueError. If the exception is raised correctly, then control goes into the except block where we return from the test. Since the test method returned successfully, it is marked as passing. If the exception is not raised, then the fail method gets called. This is another method provided by unittest.TestCase and raises a test failure exception when it is called. We can pass in a message to provide some...

Exploring assert methods


Now we have just one requirement for update remaining:

  • -Done- It should take a timestamp and price value and set it on the object

  • -Done- The price cannot be negative

  • After multiple updates, the object gives us the latest price

Let us take the remaining requirement. Here is the test:

    def test_stock_price_should_give_the_latest_price(self):
        goog = Stock("GOOG")
        goog.update(datetime(2014, 2, 12), price=10)
        goog.update(datetime(2014, 2, 13), price=8.4)
        self.assertAlmostEqual(8.4, goog.price, delta=0.0001)

What this test does is to simply call update twice, and when we ask for the price, provide us with the newer one. The interesting point about the test is that we use the assertAlmostEqual method here. This method is often used when checking equality with floating point numbers. Why don't we use plain old assertEqual? The reason is that due to the way floating points are stored, the result may not be exactly the number you expect. There...

Specific asserts versus generic asserts


One question that might come to your mind is why there are so many different assert methods. Why can't we just use assertTrue instead of the more specific assert, as shown in the following code:

assertInSeq(x, seq)
assertTrue(x in seq)

assertEqual(10, x)
assertTrue(x == 10)

While they are certainly equivalent, one motivation for using a specific assert is that you get a better error message if the assertion fails. When comparing objects like lists and dicts, the error message will show exactly where the difference occurs, making it much easier to understand. Therefore, it is recommended to use the more specific asserts wherever possible.

Setup and teardown


Let us take a look at the tests that we have done so far:

    def test_price_of_a_new_stock_class_should_be_None(self):
        stock = Stock("GOOG")
        self.assertIsNone(stock.price)

    def test_stock_update(self):
        """An update should set the price on the stock object
        We will be using the `datetime` module for the timestamp
        """
        goog = Stock("GOOG")
        goog.update(datetime(2014, 2, 12), price=10)
        self.assertEqual(10, goog.price)

    def test_negative_price_should_throw_ValueError(self):
        goog = Stock("GOOG")
        with self.assertRaises(ValueError):
            goog.update(datetime(2014, 2, 13), -1)

    def test_stock_price_should_give_the_latest_price(self):
        goog = Stock("GOOG")
        goog.update(datetime(2014, 2, 12), price=10)
        goog.update(datetime(2014, 2, 13), price=8.4)
        self.assertAlmostEqual(8.4, goog.price, delta=0.0001)

If you notice, each test does the same setup by instantiating...

Brittle tests


We've implemented the three requirements for the update method:

  • -Done- It should take a timestamp and price value and set it on the object

  • -Done- After multiple updates, the object gives us the latest price

  • -Done- The price cannot be negative

Now, let us suppose that a new requirement comes up that we had not known about before:

  • The Stock class needs a method to check if the stock has an increasing trend. An increasing trend is one where each of the latest three updates is an increase over the previous one.

So far, our Stock implementation just stores the latest price. In order to implement this functionality, we need to store some history of past price values. One way to do this is to change the price variable to a list. The problem is that when we change the internals of our implementation, it would break all of our tests, because all of them access the price variable directly and assert that it has specific values.

What we see here is an example of test brittleness.

A test is...

Left arrow icon Right arrow icon

Key benefits

  • Write robust and easily maintainable code using the principles of test driven development
  • Get solutions to real-world problems faced by Python developers
  • Go from a unit testing beginner to a master through a series of step-by-step tutorials that are easy to follow

Description

This book starts with a look at the test-driven development process, and how it is different from the traditional way of writing code. All the concepts are presented in the context of a real application that is developed in a step-by-step manner over the course of the book. While exploring the common types of smelly code, we will go back into our example project and clean up the smells that we find. Additionally, we will use mocking to implement the parts of our example project that depend on other systems. Towards the end of the book, we'll take a look at the most common patterns and anti-patterns associated with test-driven development, including integration of test results into the development process.

Who is this book for?

This book is intended for Python developers who want to use the principles of test-driven development (TDD) to create efficient and robust applications. In order to get the best out of this book, you should have development experience with Python.

What you will learn

  • Implement the test-driven development process in Python applications
  • Fully leverage Python s powerful built-in unittest and doctest modules
  • Effectively add features to existing code bases that do not have any tests
  • Safely resolve problems with the code and design, without breaking any functionality
  • Utilize Python s powerful mock and patch functionality to test complex interactions
  • Integrate unit testing into the overall software delivery process
  • Use doctest to test code with examples
  • Enhance TDD with the nose2 test runner

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Apr 29, 2015
Length: 264 pages
Edition : 1st
Language : English
ISBN-13 : 9781783987931
Languages :
Tools :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
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
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Apr 29, 2015
Length: 264 pages
Edition : 1st
Language : English
ISBN-13 : 9781783987931
Languages :
Tools :

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 $ 164.97
Functional Python Programming
$54.99
Test Driven Python Development
$54.99
Python 3 Object-Oriented Programming - Second Edition
$54.99
Total $ 164.97 Stars icon

Table of Contents

13 Chapters
1. Getting Started with Test-Driven Development Chevron down icon Chevron up icon
2. Red-Green-Refactor – The TDD Cycle Chevron down icon Chevron up icon
3. Code Smells and Refactoring Chevron down icon Chevron up icon
4. Using Mock Objects to Test Interactions Chevron down icon Chevron up icon
5. Working with Legacy Code Chevron down icon Chevron up icon
6. Maintaining Your Test Suite Chevron down icon Chevron up icon
7. Executable Documentation with doctest Chevron down icon Chevron up icon
8. Extending unittest with nose2 Chevron down icon Chevron up icon
9. Unit Testing Patterns Chevron down icon Chevron up icon
10. Tools to Improve Test-Driven Development Chevron down icon Chevron up icon
A. Answers to Exercises Chevron down icon Chevron up icon
B. Working with Older Python Versions 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 Full star icon Half star icon 4.4
(5 Ratings)
5 star 60%
4 star 20%
3 star 20%
2 star 0%
1 star 0%
Miguel Rentes Jun 01, 2015
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book provides an excellent learning artifact and reference to the Test-Driven Development practice. Even if you have already used TDD in your software projects or continue to use it, you will benefit a lot of reading this book, because it will show you how to take the most out of using TDD with Python's unittest built-in module in a simple software application to follow. The book is also very easy and accessible to read. It makes the reader acknowledge all the power of TDD and the tools the author uses to extend the TDD practice is a value asset to use on any software project.Why this is a great book to me:- The TDD approach is carefully explained and the importance of using it in our software projects;- The software application the author uses as an example on how to use TDD is simple to understand, and it is a real world software application, not an abstract example; We go carefully into every module of this application while improving our application with TDD;- This book covers Refactoring Patterns and Anti-Patterns and how to avoid recurrent Code Smells;- Explains how to use Mock Objects to test interactions between multiple objects;- Tells us how to deal with legacy code which have no tests. This is a must-read chapter!- Shows us how to maintain our test suite with docstrings, custom test class hierarchies, fixtures, helper methods, custom assert matches, equality functions and matchers to make our code more readable;- Covers executable documentation with Python's doctest module, on methods, classes, modules and packages;- Shows us how to extend Python's unittest with nose2, a powerful third-party tool and plugin suite;- Covers Unit Test Patterns, from Mocking Patterns, Spies, Generator functions, to Mocking with Mutable Arguments;- A rich set of powerful tools is gathered in this book: from third-party tools and Python's built-in modules, build tools, packaging tools, continuous integration tools, documentation tools and current TDD IDE integration;- Python 3.4 throughout this book, although the author has compiled an annex on how to use the code samples in Python 2.6 as well.Overall, this is a great book to read and to use in every software development process. After reading this book I can't think of any reason why any software projects shouldn't have tests anymore, and shouldn't be continuous integrated as well. This book shows exactly how to achieve the best out of the TDD approach with the current tools in Python 3. It's well worth a read and to have at hand, no doubt.
Amazon Verified review Amazon
Sergio Mar 09, 2017
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Great book walking you through abstract TTD concepts with Python. Would love to see some examples in different production environments and maybe a chapter on how to do this in large scale production environments.
Amazon Verified review Amazon
tb May 01, 2019
Full star icon Full star icon Full star icon Full star icon Full star icon 5
If I can save dollars by purchasing from a reseller, and I do not need the book immediately, I will. The book arrived as described!
Amazon Verified review Amazon
Jacob Zimmerman Jun 01, 2015
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Cons:- Kindle format text is WAY too big (at least on my device) - they're looking into getting this fixed if they can- Packt Publishing didn't do the best job with editing. There are quite a few (not a LOT, but enough to be a bit annoying) mistakes of all kinds. Missing words, code mistakes, typos, etc.- A TDD book that only starts off showing TDD, then mostly doesn't show tests until after showing the code.Pros:+ Great at introducing TDD and unit testing in python, then really digging into the more advanced stuff.+ First thing I've found that explains Python's built-in mocking framework very well.+ Doesn't repeat too much and doesn't move too quicklyNote: Only 3 or 4 (out of 10) chapters are truly about TDD as opposed to just unit testing. It's up to you whether this is good or bad.
Amazon Verified review Amazon
tony Jul 27, 2015
Full star icon Full star icon Full star icon Empty star icon Empty star icon 3
I was really excited to review this book. I've already read the Django TDD book by Henry Percival and covered the Testing Python book by David Sale, they were both really informative and covered TDD principles and tools in a manner I found clear and easy to understand. That being said, this book started to lose me around the 3rd chapter. Here's my analysis:Pros:-The author covers a lot of really good topics related to TDD. Code smells, refactoring, how to address a pre-existing code base that you're walking into for the first time were all topics I found to be really helpful.-The book challenged me to learn about Python topics that I had not previously known about. I wasn't sure how @classmethod worked or what the setUpClass method did in unittesting, but I certainly looked them up when the book presented them to me and was sure to fully understand them before proceeding.-The code coverage is available on GitHub, which is always great, so you can follow along easily.Cons:-I felt like the organization of the book started to slack around the 2nd chapter in Exploring the Rule classes. The whole point of TDD is for the programmer to write the tests first and the implementation code 2nd. We make the tests fail, we write code until it passes, we move on. Then we refactor. Great. Why, in the 2nd chapter, are we then presented with implementation code (no tests), then a discussion of TDD principles, followed by "here's the tests and they should pass".-Further to this point, it started to get difficult to read in chapter 3 which begins discussion of a new functionality, dual crossover moving average. Immediately, we get the implementation code (again, no tests) followed by a discussion about renaming variable and renaming method refactoring methods, both of which involve running the tests first to make sure they pass. When it comes time to implement this code, the author simply says "the tests are in the exercise section". So I'm supposed to read up to that point, then skip to the end to check out the exercises and get the tests, then go back and continue working on the code base? Furthermore, I am looking at the exercises as I type this and there is no presentation of those tests whatsoever.-Finally, while the book does cover some good topics, there are times when it gets a little off topic (I guess). For instance, in the section regarding commenting styles, we begin discussion about how to properly write comments (of course). However, rather than applying this to the current code base and application we are working on, the author gives an example of determining if people are old enough to receive a senior citizen discount. I know this is a simple example, but why switch gears when we could have easily applied this to what was being worked on (there was a presentation of a very poorly written method at the beginning of the chapter). All in all, I wouldn't say this was a poor book, I've read some O'Reilly work that could make you want to quit programming altogether, but I do think there could be some effective revisions to make it easier to read and understand. I have a lot of respect for authors who decide to take on TDD as it is a discipline and requires constant effort and attention. That being said, I would recommend this book to review the principles and topics discussed, but not necessarily to follow along in a step by step manner.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.

Modal Close icon
Modal Close icon