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

eBook
$38.99 $43.99
Paperback
$54.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
OR
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

Test Driven Python Development

Chapter 1. Getting Started with Test-Driven Development

My first encounter with Test-Driven Development (TDD) was back in 2002. At that time, it wasn't as mainstream as it is today, and I remember watching two developers writing some tests first and then implementing the functionality later. I thought it to be quite a strange way to write a code, and I promptly forgot about it. It was not until 2004, when I was involved with a challenging project, that I remembered TDD again. We were faced with a messy code that was difficult to test and every change seemed to create a series of new bugs. I thought, why not give TDD a shot and see how it worked? Suffice to say, TDD changed my outlook on software development. We stopped writing messy spaghetti code, and started writing better designed, more maintainable code. Regression failures dropped drastically. I was hooked.

Perhaps, like me, you face some challenges in a project and want to see how TDD can help you. Or, maybe you've heard a lot of people in the industry sing the praises of TDD and you're wondering what all the fuss is about. Maybe you've been reading about how TDD will be an essential skill in the near future, and want to get up to speed on it. No matter what your motivation, I hope this book will help you reach your goal.

TDD is a lot more than just a library or an API; it is a different way of developing software. In this book, we'll discuss how to apply this process to writing Python software. We're in luck, because Python has fantastic support for TDD right out of the box. In fact, unit testing has been an integral part of the Python standard library from the Python 2.1 release back in April 2001. Numerous improvements have been added since then, and the latest version that ships with Python 3.4 has a ton of exciting features that we'll explore over the course of this book.

Prerequisites

We will be using Python 3.4 in this book. Most of the techniques will work on Python 2.6+ as well, but some small changes may be required to the examples presented in this book in order to make them run. The Appendix B, Working with Older Python Versions lists these changes.

This book assumes that the reader has an intermediate level of Python understanding. In this book, we will be using Python language features such as lambdas, decorators, generators, and properties, and we assume that the reader is familiar with them. While we will give a brief description of these features as we encounter them, this book will not go into a lot of details about how they work, choosing instead to focus on how to test such code.

Note

Note that if you have only Python 2.x installed on your system, then go to http://python.org and download the latest release in the Python 3.4 series. For Linux users, if Python 3.4 is not installed on your system, then check your distribution's package repository to get the latest version. If no package exists, or you are using a non-standard or older version of a distribution, then you might have to compile it from source. The instructions to do so are available at https://docs.python.org/devguide/setup.html.

Since TDD is a hands-on coding activity, this book will use a lot of code snippets throughout. We recommend that you follow along by typing the code and running it yourself. It is much easier to understand the code and concepts when you can see it working (or not working) in front of you, rather than just reading through the code in this book.

Tip

Getting the code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. 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.

All the code in this book can be found online at https://github.com/siddhi/test_driven_python. You can select a specific branch of the repository to get the code for the start of this chapter, and work through this chapter from that starting point. You can also select a tag on the branch to get the code for the endpoint of this chapter, if you would prefer to jump to the end of the code.

Understanding test-driven development

After all the hype in the previous paragraphs, you might be wondering what exactly test-driven development is all about, and whether it is some complex procedure that requires a lot of skill to implement. Actually, test-driven development is very simple. The flowchart below shows the three steps in the process.

Understanding test-driven development

Let's walk through the preceding flowchart in a little more detail.

  • Red: The first step is to write a small unit test case. As we have only written the test and haven't written the implementation yet, this test will naturally fail.
  • Green: Next, we write the code that implements the desired functionality. At this point, we aren't looking to create the best design or the most readable code. We just want something simple that will pass the test.
  • Refactor: Now that the test is passing, we go back and look at the code to see whether it can be improved. This may involve improving the design, or making it more readable or maintainable. We can use the tests written so far to ensure that we aren't breaking anything during the refactoring step.
  • The cycle repeats as we proceed to the next test and implement the next bit of functionality.

Developers who are familiar with TDD usually go through this cycle many times an hour, implementing small steps of functionality each time.

TDD versus unit testing versus integration testing

Before we go further, let's take a short detour to define some terms and understand the differences between them. It is very easy to get confused between these terms, and they are often used with different meanings in different places.

In the broadest sense of the term, unit testing simply means testing a single unit of code, isolated from other code that it might be integrated with. Traditionally, unit testing was an activity that was primarily performed by test engineers. These engineers would take code given by the developers and run them through a suite of tests to verify that the code worked. Since this code was tested before integration, the process fits into the definition of a unit test. Traditional unit testing was typically a manual affair, with test engineers walking through the tests cases by hand, although some teams would go a step further and automate the tests.

An integration test is a test that involves exercising more than one unit of the system. The goal is to check whether these units have been integrated correctly. A typical integration test might be to go to a web page, fill in a form, and check whether the right message is displayed on the screen. In order for this test to pass, the UI must show the form correctly, the input must be captured correctly, and that input must be passed on to any logic processing. The steps might involve reading and writing from a database before a message is generated and the UI has to display it correctly. Only if all these interactions succeed will the integration test pass. If any one step should fail, the integration test will fail.

At this point, a valid question would be to ask why we need unit testing at all. Why not write only integration tests, where a single test could check so many parts of the application at once? The reason is that integration tests do not pinpoint the location of failure. A failing integration test could have an error in the UI, or in the logic, or somewhere in the way data is read or written. It will take a lot of investigation to see where the error is and fix it. By contrast, with well-written unit tests, a failing unit test will pinpoint exactly what is failing. Developers can go right to the point and fix the error.

Along the way, teams started moving to a process where developers themselves wrote tests for the code that they had implemented. These tests would be written after the developer had finished the implementation, and helped verify that the code worked as expected. These tests were usually automated. Such a process is generally called developer testing or developer unit testing.

TDD takes developer tests one step further, by writing the test before starting the implementation.

  • Developer tests: Any kind of automated unit tests written by the developer, either before or after functionality is implemented.
  • Unit testing: Any kind of testing of a particular unit of an application, either by a developer or a tester. These tests might be automated, or run manually.
  • Integration testing: Any kind of testing that involves two or more units working together. These tests are typically performed by a tester, but they could be done by a developer as well. These tests might be manual or automated.

As we can see, unit testing is a general term, whereas developer testing is a specific subset of unit testing, and TDD is a specific form of developer testing.

On the surface, traditional unit testing, developer testing and TDD look similar. They all appear to be about writing tests for a single unit of code, with only minor variations based on who writes the test and whether the tests are written before the code or after.

However, dig deeper and differences appear. First, the intent is vastly different. Traditional unit testing and developer testing are all about writing tests to verify that the code works as it is supposed to. On the other hand, the main focus of TDD is not really about testing. The simple act of writing a test before the implementation changes the way we think when we implement the corresponding functionality. The resulting code is more testable, usually has a simple and elegant design, and is more maintainable and readable. This is because making a class easy to test also encourages good design practices, such as decoupling dependencies and writing small, modular classes.

Thus, one can say that TDD is all about writing better code, and it is just a happy side effect that we end up with a fully automated test suite as an outcome.

This difference in intent manifests itself in the type of tests. Developer testing usually results in large test cases, with a hefty part of the test code involved in test setup. By contrast, tests written using TDD are very small and numerous. Some people like to call them micro tests to differentiate them from other developer tests or traditional unit tests. TDD-style unit tests also try to be very fast to run because they are executed every few minutes during the development process.

Finally, the tests that are written in TDD are those that drive the development forward, and not necessarily those that cover all imaginable scenarios. For example, a function that is supposed to process a file might have tests to handle cases when the file exists or it doesn't exist, but probably won't have tests to see what happens if the file is 1 terabyte in size. The latter is something that a tester might conceivably test for, but would be an unusual test in TDD unless the function is clearly expected to work with such a file.

This really highlights the difference between TDD and other forms of unit testing.

Note

TDD is about writing better, cleaner, more maintainable code, and only incidentally about testing.

Using TDD to build a stock alert application

Over the course of this book, we are going to be using TDD to build a simple stock alert application. The application will listen to stock updates from a source. The source can be anything—a server on the Internet, or a file on the hard drive, or something else. We will be able to define rules, and when the rule is matched, the application sends us an email or text message.

For example, we could define a rule as "If AAPL crosses the $550 level then send me an email". Once defined, the application will monitor updates and send an e-mail when the rule is matched.

Writing our first test

Enough talk. Let's get started with our application. What is a good place to start? From examining the application description mentioned earlier, it looks like we will need the following modules:

  • Some way to read stock price updates, either from the Internet or from a file
  • A way to manage the stock information so that we can process it
  • A way to define rules and match them against the current stock information
  • A way to send an email or text message when a rule is matched

Based on these requirements, we will be using the following design:

Writing our first test

Each term is discussed as follows:

  • Alert: This is the core of the application. An alert will take a Rule and map it to an Action. When the rule is matched, the action is executed.
  • Rule: A Rule contains the condition we want to check for. We should get alerted when the rule is matched.
  • Action: This is the action to be performed when the rule is matched. This could be as simple as printing a message on the screen, or, in more real-work scenarios, we might send an e-mail or a text message.
  • Stock: The Stock class keeps track of the current price and possibly a history of the prices for a stock. It sends an Event to the Alert when there is an update. The alert then checks if it's rule matched and whether any action needs to be executed.
  • Event: This class is used to send events to the Alert when a Stock is updated.
  • Processor: The processor takes stock updates from the Reader and updates the Stock with the latest data. Updating the stock causes the event to be fired, which, in turn, causes the alert to check for a rule match.
  • Reader: The Reader gets the stock alerts from some source. In this book, we are going to get updates from a simple list or a file, but you can build other readers to get updates from the Internet or elsewhere.

Among all these classes, the way to manage stock information seems to be the simplest, so let's start there. What we are going to do is to create a Stock class. This class will hold information about the current stock. It will store the current price and possibly some recent price history. We can then use this class when we want to match rules later on.

To get started, create a directory called src. This directory is going to hold all our source code. In the rest of this book, we will refer to this directory as the project root. Inside the src directory, create a subdirectory called stock_alerter. This is the directory in which we are going to implement our stock alert module.

Okay, let's get started with implementing the class.

NO! Wait! Remember the TDD process that was described earlier? The first step is to write a test, before we code the implementation. By writing the test first, we now have the opportunity to think about what we want this class to do.

So what exactly do we want this class to do? Let's start with something simple:

  • A Stock class should be instantiated with the ticker symbol
  • Once instantiated, and before any updates, the price should be None

Of course, there are many more things we will want this class to do, but we'll think about them later. Rather than coming up with a very comprehensive list of functionality, we're going to focus on tiny bits of functionality, one at a time. For now, the preceding expectation is good enough.

To convert the preceding expectation into code, create a file called stock.py in the project root, and put the following code in it:

import unittest
class StockTest(unittest.TestCase):
    def test_price_of_a_new_stock_class_should_be_None(self):
        stock = Stock("GOOG")
        self.assertIsNone(stock.price)
if __name__ == "__main__":
    unittest.main()

What does this code do?

  1. First, we import unittest. This is the library that has the test framework that we are going to use. Luckily for us, it is bundled into the Python standard library by default and is always available, so we don't need to install anything, we can just import the module directly.
  2. Second, we create a class StockTest. This class will hold all the test cases for the Stock class. This is just a convenient way of grouping related tests together. There is no rule that every class should have a corresponding test class. Sometimes, if we have a lot of tests for a class, then we may want to create separate test classes for each individual behavior, or group the tests some other way. However, in most cases, creating one test class for an actual class is the best way to go about it.
  3. Our StockTest class inherits from the TestCase class in the unittest module. All tests need to inherit from this class in order to be identified as a test class.
  4. Inside the class, we have one method. This method is a test case. The unittest framework will pick up any method that starts with test. The method has a name that describes what the test is checking for. This is just so that when we come back after a few months, we still remember what the test does.
  5. The test creates a Stock object and then checks if the price is None. assertIsNone is a method provided by the TestCase class that we are inheriting from. It checks that its parameter is None. If the parameter is not None, it raises an AssertionError and fails the test. Otherwise, execution continues to the next line. Since that is the last line of the method, the test completes and is marked as a pass.
  6. The last segment checks if the module was executed directly from the command line. In such a case, the __name__ variable will have the value __main__, and the code will execute the unittest.main() function. This function will scan the current file for all tests and execute them. The reason we need to wrap this function call inside the conditional is because this part does not get executed if the module is imported into another file.

Congratulations! You have your first failing test. Normally, a failing test would be a cause for worry, but in this case, a failing test means that we're done with the first step of the process and can move on to the next step.

Analyzing the test output

Now that we've written our test, it is time to run it. To run the test, just execute the file. Assuming that the current directory is the src directory, the following is the command to execute the file:

  • Windows:
    python.exe stock_alerter\stock.py
    
  • Linux/Mac:
    python3 stock_alerter/stock.py
    

If the python executable is not on your path, then you will have to give the full path to the executable here. In some Linux distributions, the file may be called python34 or python3.4 instead of python3.

When we run the file, the output looks like the following:

E
=====================================================================
ERROR: test_price_of_a_new_stock_class_should_be_None (__main__.StockTest)
---------------------------------------------------------------------
Traceback (most recent call last):
  File "stock_alerter\stock.py", line 6, in test_price_of_a_new_stock_class_should_be_None
    stock = Stock("GOOG")
NameError: name 'Stock' is not defined
---------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

As expected, the test fails, because we haven't created the Stock class yet.

Let's look at that output in a little more detail:

  • E on the first line signifies that the test gave an error. If a test passed, then you would have a dot on that line. A failed test would be marked with F. Since we have only a single test, there is only one character there. When we have multiple tests, then the status of each test will be displayed on that line, one character per test.
  • After all the test statuses are displayed, we get a more detailed explanation of any test errors and failures. It tells us whether there was a failure or an error (in this case denoted by ERROR) followed by the name of the test and which class it belongs to. This is followed by a traceback, so we know where the failure occurred.
  • Finally, there is a summary that shows how many tests were executed, how many passed or failed, and how many gave errors.

Test errors versus test failures

There are two reasons why a test might not pass: It might have failed or it might have caused an error. There is a small difference between these two. A failure indicates that we expected some outcome (usually via an assert), but got something else. For example, in our test, we are asserting that stock.price is None. Suppose stock.price has some other value apart from None, then the test will fail.

An error indicates that something unexpected happened, usually an unexpected exception was raised. In our previous example, we got an error because the Stock class has not yet been defined.

In both the cases, the test does not pass, but for different reasons, and these are reported separately as test failures and test errors.

Making the test pass

Now that we have a failing test, let's make it pass. Add the following code to the stock.py file, after the import unittest line:

class Stock:
    def __init__(self, symbol):
        self.symbol = symbol
        self.price = None

What we have done here is to implement just enough code to pass the test. We've created the Stock class so the test shouldn't complain about it being missing, and we've initialized the price attribute to None.

What about the rest of the implementation for this class? This can wait. Our main focus right now is to pass the current expectation for this class. As we write more tests, we will end up implementing more of the class as well.

Run the file again, and this time the output should be like the following:

.
---------------------------------------------------------------------
Ran 1 test in 0.000s

OK

We've got a dot in the first line, which signifies that the test is passing. The OK message at the end tells us that all tests have passed.

The final step is to refactor the code. With so little code, there is really nothing much to clean up. So, we can skip the refactoring step and start with the next test.

Reorganizing the test code

We've added the test cases in the same file as the code. This is a good, simple way to add test cases to standalone scripts and applications that are not too complex. However, for larger applications, it is a good idea to keep test code separate from production code.

There are two common patterns for organizing test code this way.

The first pattern is to keep test code in a separate root directory, as shown in the following:

root
|
+- package
|  |
|  +- file1
|  +- file2
|
+- test
   |
   +- test_file1
   +- test_file2

The other pattern is to keep test code as a submodule of the main code, as shown in the following:

root
|
+- package
   |
   +- file1
   +- file2
   +- test
      |
      +- test_file1
      +- test_file2

The first pattern is commonly used for standalone modules as it allows us to distribute the code and tests together. Tests can generally be run without having to perform a lot of setup or configuration. The second pattern has an advantage when the application has to be packaged without the test code, for example when deploying to production servers, or distributing to customers (in the case of a commercial application). However, both the patterns are in popular use, and it is mainly a personal preference as to which method to use.

We are going to follow the first pattern in this book. To get started, create a directory called tests inside the stock_alerter directory. Next, create a file called test_stock.py in this directory. We will put all our test cases in one-to-one correspondence with the source file. This means, a file called sample.py will have its test cases in the tests/test_sample.py file. This is a simple naming convention that helps to quickly locate test cases.

Finally, we move our test cases into this file. We also need to import the Stock class to be able to use it in the test case. Our test_stock.py file now looks like the following:

import unittest
from ..stock import Stock

class StockTest(unittest.TestCase):
    def test_price_of_a_new_stock_class_should_be_None(self):
        stock = Stock("GOOG")
        self.assertIsNone(stock.price)

Remember to remove the import unittest line from stock.py, now that it no longer contains the test code. Previously we had just one standalone script, but we now have a stock_alerter module and a stock_alerter.tests submodule. Since we are now working with modules, we should also add in an empty __init__.py file in both the stock_alerter and tests directories.

Our file layout should now be like the following:

src
|
+- stock_alerter
   |
   +- __init__.py
   +- stock.py
   +- tests
      +- __init__.py
      +- test_stock.py

Running the tests after the reorganization

If you have noticed, we no longer have a call to unittest.main() in the test code. Including a call to unittest.main() works well with individual scripts since it allows us to run the tests by simply executing the file. However, it is not a very scalable solution. If we have hundreds of files, we would like to run all the tests at once, and not have to execute each file individually.

To address this, Python 3 comes with a very nice test discovery and execution capability from the command line. Simply go into the src directory and run the following command:

  • Windows:
    python.exe -m unittest
    
  • Linux/Mac:
    python3 -m unittest
    

This command will go through the current directory and all subdirectories and run all the tests that are found. This is the default autodiscover mode of execution, where the command searches all the files and runs the tests. Autodiscovery can also be explicitly run with the following command:

python3 -m unittest discover

Autodiscover can be customized to check in specific directories or files with the following parameters:

  • -s start_directory: Specify the start directory from where the discovery should start. This defaults to the current directory.
  • -t top_directory: Specify the top-level directory. This is the directory from which imports are performed. This is important if the start directory is inside the package and you get errors due to incorrect imports. This defaults to the start directory.
  • -p file_pattern: The file pattern that identifies test files. By default it checks for python files that start with test. If we name our test files something else (for example, stock_test.py), then we have to pass in this parameter so that the file is correctly identified as a test file.

To illustrate the difference between the start and top directory, run the following command from the src directory:

python3 -m unittest discover -s stock_alerter

The preceding command will fail with an import error. The reason is because when the start directory is set to stock_alerter, then the tests directory is imported as a top-level module, and the relative import fails. To get around this, we need to use the following command:

python3 -m unittest discover -s stock_alerter -t .

This command will import all modules relative to the top directory, and so stock_alerter correctly becomes the main module.

You can also disable autodiscovery and specify only certain tests to be run:

  • Passing in a module name will only run the tests within that module. For example, python3 -m unittest stock_alerter.tests.test_stock will run the tests only in test_stock.py.
  • You can further refine to a specific class or method, such as python3 -m unittest stock_alerter.tests.test_stock.StockTest.

Summary

Congratulations! You've completed one cycle of TDD. As you can see, each cycle is very quick. Some cycles, like the one we've just gone through, can be completed in a few seconds. Other cycles might involve a fair amount of cleanup and can take quite a long time. Each cycle will implement a small test, a small bit of functionality to pass the test, and then some cleanup to make the code of high quality.

In this chapter, we looked at what TDD is, how it is different from other forms of unit and integration testing, and wrote our first test.

At this point, our implementation is still very small and very simple. You might be wondering if it is worth all this hype just to write and implement four lines of very simple code. In the next few chapters, we'll progress further with the examples and go more in-depth into the process.

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
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 29, 2015
Length: 264 pages
Edition : 1st
Language : English
ISBN-13 : 9781783987924
Languages :
Tools :

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
OR
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 29, 2015
Length: 264 pages
Edition : 1st
Language : English
ISBN-13 : 9781783987924
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

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