Table of Contents for
Test-Driven Development with Python, 2nd Edition

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Test-Driven Development with Python, 2nd Edition by Harry J.W. Percival Published by O'Reilly Media, Inc., 2017
  1. Cover
  2. nav
  3. Praise for Test-Driven Development with Python
  4. Test-Driven Development with Python
  5. Test-Driven Development with Python
  6. Preface
  7. Prerequisites and Assumptions
  8. Companion Video
  9. Acknowledgments
  10. I. The Basics of TDD and Django
  11. 1. Getting Django Set Up Using a Functional Test
  12. 2. Extending Our Functional Test Using the unittest Module
  13. 3. Testing a Simple Home Page with Unit Tests
  14. 4. What Are We Doing with All These Tests? (And, Refactoring)
  15. 5. Saving User Input: Testing the Database
  16. 6. Improving Functional Tests: Ensuring Isolation and Removing Voodoo Sleeps
  17. 7. Working Incrementally
  18. II. Web Development Sine Qua Nons
  19. 8. Prettification: Layout and Styling, and What to Test About It
  20. 9. Testing Deployment Using a Staging Site
  21. 10. Getting to a Production-Ready Deployment
  22. 11. Automating Deployment with Fabric
  23. 12. Splitting Our Tests into Multiple Files, and a Generic Wait Helper
  24. 13. Validation at the Database Layer
  25. 14. A Simple Form
  26. 15. More Advanced Forms
  27. 16. Dipping Our Toes, Very Tentatively, into JavaScript
  28. 17. Deploying Our New Code
  29. III. More Advanced Topics in Testing
  30. 18. User Authentication, Spiking, and De-Spiking
  31. 19. Using Mocks to Test External Dependencies or Reduce Duplication
  32. 20. Test Fixtures and a Decorator for Explicit Waits
  33. 21. Server-Side Debugging
  34. 22. Finishing “My Lists”: Outside-In TDD
  35. 23. Test Isolation, and “Listening to Your Tests”
  36. 24. Continuous Integration (CI)
  37. 25. The Token Social Bit, the Page Pattern, and an Exercise for the Reader
  38. 26. Fast Tests, Slow Tests, and Hot Lava
  39. Obey the Testing Goat!
  40. A. PythonAnywhere
  41. B. Django Class-Based Views
  42. C. Provisioning with Ansible
  43. D. Testing Database Migrations
  44. E. Behaviour-Driven Development (BDD)
  45. F. Building a REST API: JSON, Ajax, and Mocking with JavaScript
  46. G. Django-Rest-Framework
  47. H. Cheat Sheet
  48. I. What to Do Next
  49. J. Source Code Examples
  50. Bibliography
  51. Index
  52. About the Author
  53. Colophon

Appendix I. What to Do Next

Here I offer a few suggestions for things to investigate next, to develop your testing skills, and to apply them to some of the cool new technologies in web development (at the time of writing!).

I hope to turn each one of these into at least some sort of blog post, if not a future appendix to the book. I hope to also produce code examples for all of them, as time goes by. So do check out http://www.obeythetestinggoat.com, and see if there are any updates.

Or, why not try to beat me to it, and write your own blog post chronicling your attempt at any one of these?

I’m very happy to answer questions and provide tips and guidance on all these topics, so if you find yourself attempting one and getting stuck, please don’t hesitate to get in touch at obeythetestinggoat@gmail.com!

Notifications—Both on the Site and by Email

It would be nice if users were notified when someone shares a list with them.

You can use django-notifications to show a message to users the next time they refresh the screen. You’ll need two browsers in your FT for this.

And/or, you could send notifications by email. Investigate Django’s email test capabilities. Then, decide this is so critical that you need real tests with real emails. Use the IMAPClient library to fetch actual emails from a test webmail account.

Switch to Postgres

SQLite is a wonderful little database, but it won’t deal well once you have more than one web worker process fielding your site’s requests. Postgres is everyone’s favourite database these days, so find out how to install and configure it.

You’ll need to figure out a place to store the usernames and passwords for your local, staging, and production Postgres servers. Since, for security, you probably don’t want them in your code repository, look into ways of modifying your deploy scripts to pass them in at the command line. Environment variables are one popular solution for where to keep them…

Experiment with keeping your unit tests running with SQLite, and compare how much faster they are than running against Postgres. Set it up so that your local machine uses SQLite for testing, but your CI server uses Postgres.

Run Your Tests Against Different Browsers

Selenium supports all sorts of different browsers, including Chrome and Internet Exploder. Try them both out and see if your FT suite behaves any differently.

You should also check out a “headless” browser like PhantomJS.

In my experience, switching browsers tends to expose all sorts of race conditions in Selenium tests, and you will probably need to use the interaction/wait pattern a lot more (particularly for PhantomJS).

404 and 500 Tests

A professional site needs good-looking error pages. Testing a 404 page is easy, but you’ll probably need a custom “raise an exception on purpose” view to test the 500 page.

The Django Admin Site

Imagine a story where a user emails you wanting to “claim” an anonymous list. Let’s say we implement a manual solution to this, involving the site administrator manually changing the record using the Django admin site.

Find out how to switch on the admin site, and have a play with it. Write an FT that shows a normal, non–logged-in user creating a list, then have an admin user log in, go to the admin site, and assign the list to the user. The user can then see it in their “My Lists” page.

Write Some Security Tests

Expand on the login, my lists, and sharing tests—what do you need to write to assure yourself that users can only do what they’re authorized to?

Test for Graceful Degradation

What would happen if Persona went down? Can we at least show an apologetic error message to our users?

  • Tip: one way of simulating Persona being down is to hack your hosts file (at /etc/hosts or c:\Windows\System32\drivers\etc). Remember to revert it in the test tearDown!

  • Think about the server side as well as the client side.

Caching and Performance Testing

Find out how to install and configure memcached. Find out how to use Apache’s ab to run a performance test. How does it perform with and without caching? Can you write an automated test that will fail if caching is not enabled? What about the dreaded problem of cache invalidation? Can tests help you to make sure your cache invalidation logic is solid?

JavaScript MVC Frameworks

JavaScript libraries that let you implement a Model-View-Controller pattern on the client side are all the rage these days. To-do lists are one of the favourite demo applications for them, so it should be pretty easy to convert the site to being a single-page site, where all list additions happen in JavaScript.

Pick a framework—perhaps Backbone.js or Angular.js—and spike in an implementation. Each framework has its own preferences for how to write unit tests, so learn the one that goes along with it, and see how you like it.

Async and Websockets

Supposing two users are working on the same list at the same time. Wouldn’t it be nice to see real-time updates, so if the other person adds an item to the list, you see it immediately? A persistent connection between client and server using websockets is the way to get this to work.

Check out one of the Python async web servers—Tornado, gevent, Twisted—and see if you can use it to implement dynamic notifications.

To test it, you’ll need two browser instances (like we used for the list sharing tests), and check that notifications of the actions from one appear in the other, without needing to refresh the page…

Switch to Using py.test

py.test lets you write unit tests with less boilerplate. Try converting some of your unit tests to using py.test. You may need to use a plugin to get it to play nicely with Django.

Check Out coverage.py

Ned Batchelder’s coverage.py will tell you what your test coverage is—what percentage of your code is covered by tests. Now, in theory, because we’ve been using rigorous TDD, we should always have 100% coverage. But it’s nice to know for sure, and it’s also a very useful tool for working on projects that didn’t have tests from the beginning.

Client-Side Encryption

Here’s a fun one: what if our users are paranoid about the NSA, and decide they no longer want to trust their lists to The Cloud? Can you build a JavaScript encryption system, where the user can enter a password to encypher their list item text before it gets sent to the server?

One way of testing it might be to have an “administrator” user that goes to the Django admin view to inspect users’ lists, and checks that they are stored encrypted in the database.

Your Suggestion Here

What do you think I should put here? Suggestions, please!