Test-Driven Development with Python, 3rd Edition

Book description

The third edition of this trusted guide demonstrates the practical advantages of test-driven development (TDD) with Python and describes how to develop a real web application. You'll learn how to write and run tests before building each part of your app and then develop the minimum amount of code required to pass those tests. The result? Clean code that works.

In the process, author Harry Percival teaches software and web developers the basics of Django, Selenium, Git, JavaScript, and Mock libraries, along with current web development techniques. This book—updated for Python 3.11 and Django 4—clearly demonstrates how TDD encourages simple designs and inspires confidence.

Fully updated, this third edition addresses:

  • The TDD workflow, including the unit test/code cycle and refactoring
  • Unit tests for classes and functions and functional tests for user interactions within the browser
  • Mock objects and the pros and cons of isolated versus integrated tests
  • Testing and automation of deployments with a staging server
  • Tests applied to the third-party plug-ins you integrate into your site
  • Automatic tests using a continuous integration environment
  • Using TDD to build a REST API with a JavaScript frontend interface

Publisher resources

View/Submit Errata

Table of contents

  1. Brief Table of Contents (Not Yet Final)
  2. Preface
    1. Why I Wrote a Book About Test-Driven Development
    2. Aims of This Book
    3. Outline
    4. Conventions Used in This Book
    5. Submitting Errata
    6. Using Code Examples
    7. O’Reilly Online Learning
    8. How to Contact Us
    9. License for the free edition
  3. Prerequisites and Assumptions
    1. Python 3 and Programming
    2. How HTML Works
    3. Django
    4. JavaScript
    5. Required Software Installations
      1. Installing Firefox
    6. Setting Up Your Virtualenv
      1. Activating and Deactivating the Virtualenv
      2. Installing Django and Selenium
      3. Some Error Messages You’re Likely to See When You Inevitably Fail to Activate Your Virtualenv
  4. Companion Video
  5. I. The Basics of TDD and Django
  6. 1. Getting Django Set Up Using a Functional Test
    1. Obey the Testing Goat! Do Nothing Until You Have a Test
    2. Getting Django Up and Running
    3. Starting a Git Repository
  7. 2. Extending Our Functional Test Using the unittest Module
    1. Using a Functional Test to Scope Out a Minimum Viable App
    2. The Python Standard Library’s unittest Module
    3. Commit
  8. 3. Testing a Simple Home Page with Unit Tests
    1. Our First Django App, and Our First Unit Test
    2. Unit Tests, and How They Differ from Functional Tests
    3. Unit Testing in Django
    4. Django’s MVC, URLs, and View Functions
    5. Unit Testing a View
      1. At Last! We Actually Write Some Application Code!
      2. The Unit-Test/Code Cycle
    6. Our functional tests tell us we’re not quite done yet.
    7. Reading Tracebacks
    8. urls.py
  9. 4. What Are We Doing with All These Tests? (And, Refactoring)
    1. Programming Is Like Pulling a Bucket of Water Up from a Well
    2. Using Selenium to Test User Interactions
    3. The “Don’t Test Constants” Rule, and Templates to the Rescue
      1. Refactoring to Use a Template
      2. Checking template rendering
    4. On Refactoring
    5. A Little More of Our Front Page
    6. Recap: The TDD Process
      1. Double-loop TDD
  10. 5. Saving User Input: Testing the Database
    1. Wiring Up Our Form to Send a POST Request
    2. Debugging functional tests
    3. Processing a POST Request on the Server
    4. Passing Python Variables to Be Rendered in the Template
      1. An Unexpected Failure
    5. Three Strikes and Refactor
    6. The Django ORM and Our First Model
      1. Our First Database Migration
      2. The Test Gets Surprisingly Far
      3. A New Field Means a New Migration
    7. Saving the POST to the Database
    8. Redirect After a POST
    9. Better Unit Testing Practice: Each Test Should Test One Thing
    10. Rendering Items in the Template
    11. Creating Our Production Database with migrate
    12. Recap
  11. 6. Improving Functional Tests: Ensuring Isolation and Removing Voodoo Sleeps
    1. Ensuring Test Isolation in Functional Tests
      1. Running Just the Unit Tests
    2. Aside: Upgrading Selenium and Geckodriver
    3. On Implicit and Explicit Waits, and Voodoo time.sleeps
  12. 7. Working Incrementally
    1. Small Design When Necessary
      1. Not Big Design Up Front
      2. YAGNI!
      3. REST (ish)
    2. Implementing the New Design Incrementally Using TDD
    3. Ensuring We Have a Regression Test
    4. Iterating Towards the New Design
    5. Taking a First, Self-Contained Step: One New URL
      1. Separating out our home page and list view functionality
      2. The FTs detect a regression
      3. Getting Back to a Working State as Quickly as Possible
      4. Green? Refactor
    6. Another Small Step: A Separate Template for Viewing Lists
    7. A Third Small Step: A New URL for Adding List Items
      1. A Test Class for New List Creation
      2. A URL and View for New List Creation
      3. Removing Now-Redundant Code and Tests
      4. A Regression! Pointing Our Forms at the New URL
    8. Biting the Bullet: Adjusting Our Models
      1. A Foreign Key Relationship
      2. Adjusting the Rest of the World to Our New Models
    9. Each List Should Have Its Own URL
      1. Capturing Parameters from URLs
      2. Adjusting new_list to the New World
    10. The Functional Tests Detect Another Regression
    11. One More View to Handle Adding Items to an Existing List
      1. The Last New URL
      2. The Last New View
      3. Testing Template Context Directly
    12. A Final Refactor Using URL includes
  13. II. Web Development Sine Qua Nons
  14. 8. Prettification: Layout and Styling, and What to Test About It
    1. Testing Layout and Style
    2. Prettification: Using a CSS Framework
    3. Django Template Inheritance
    4. Integrating Bootstrap
      1. Rows and Columns
    5. Static Files in Django
      1. Switching to StaticLiveServerTestCase
    6. Using Bootstrap Components to Improve the Look of the Site
      1. Jumbotron!
      2. Large Inputs
      3. Table Styling
      4. Dark Modeeeeeee
      5. A semi-decent page
    7. What We Glossed Over: collectstatic and Other Static Directories
    8. A Few Things That Didn’t Make It
  15. 9. Containerization aka Docker
    1. TDD and the Danger Areas of Deployment
    2. Docker, Containers and Virtualization
      1. Docker and your CV
    3. Docker and the Danger Areas of Deployment
    4. An Overview of Our Deployment Procedure
    5. As Always, Start with a Test
      1. Making an src Folder
    6. Installing Docker
    7. Building a Docker Image and Running a Docker Container
      1. A First Cut of a Dockerfile
      2. Docker Build
      3. Docker Run
    8. Installing Django into our Virtualenv
      1. Successful Run
    9. Using the FT to Check That Our Container Works
    10. Debugging a Container Networking Problems
      1. Debugging Web Server Connectivity With “curl”
    11. Running code “inside” the container with docker exec
      1. Docker Port Mapping
      2. Essential Googling the Error Message
    12. Database migrations
      1. Should we run “migrate” inside the Dockerfile? No. // JAN: Not sure I understand this line. You’re saying that we shouldn’t run migrate inside our Dockerfile, but then in the next line you do exactly that
    13. Mounting files inside the container.
  16. 10. Making Our App Production-Ready
    1. What We Need to Do
    2. Switching to Gunicorn
      1. The FTs catch a problem with static files
    3. Serving Static Files with Whitenoise
    4. Using requirements.txt
    5. Using Environment Variables to Adjust Settings for Production
      1. Setting DEBUG=True and SECRET_KEY
      2. Setting environment variables inside the Dockerfile
      3. Setting Environment Variables at the Docker Command Line
      4. ALLOWED_HOSTS is Required When Debug Mode is Turned Off
      5. Collectstatic is Required when Debug is Turned Off
    6. Switching to a nonroot user
    7. Configuring logging
      1. Provoking a deliberate error
  17. 11. Infrastructure As Code: Automated Deployments With Ansible
    1. Getting a Domain Name
    2. Manually Provisioning a Server to Host Our Site
      1. Choosing Where to Host Our Site
      2. Spinning Up a Server
      3. User Accounts, SSH, and Privileges
    3. Configuring Domains for Staging and Live
    4. Ansible
      1. Installing Ansible
      2. A First Cut of an Ansible Playbook
    5. SSHing Into the Server and Viewing Container Logs
    6. Getting our image onto the server
    7. Using an env File to Store Our Environment Variables
      1. More debugging
    8. Mounting the database on the server and running migrations
    9. It workssss
    10. Further Reading
  18. About the Author

Product information

  • Title: Test-Driven Development with Python, 3rd Edition
  • Author(s): Harry Percival
  • Release date: July 2025
  • Publisher(s): O'Reilly Media, Inc.
  • ISBN: 9781098148713