This document discusses techniques for writing fast and efficient unit tests in Django. It emphasizes writing unit tests over integration tests to test small units of code. Some best practices for fast tests include setting up tests cautiously, avoiding database usage, using mocks to emulate dependencies, and engineering tests through tools and refactoring code under test. Focusing on test speed led the author to develop a more effective test philosophy and ultimately better code.
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
How to Write Fast and Efficient Unit Tests in Django
1. How to Write Fast and Efficient Unit
Tests in Django
Casey Kinsey
DjangoCon 2013
Monday, September 2, 13
2. A REAL NEED FORTEST SPEED
Monday, September 2, 13
3. A REAL NEED FORTEST SPEED
• Made an initial production release of a real product for a national media company
• Test coverage was not great
• Started seeing regressions in subsequent releases
• Decided to aggressively pursue greater test coverage
• Results were successful, but one thing clear: As test coverage increased we had an
acute need for faster test suites.
Monday, September 2, 13
4. WHY SHOULD I BE CONCERNED WITH
UNITTEST SPEED?
• If you’re serious about testing, you’re serious about at least two things:
• Having lots of tests
• Running those tests frequently
Monday, September 2, 13
5. •A slow test suite gets in the way of your testing goals because:
•Developers will avoid running tests
•Preparing code for integration becomes painful
•Deployment speed is directly affected
Monday, September 2, 13
6. THE FIRST STEPTO FASTER UNITTESTS:
WRITE UNITTESTS
Monday, September 2, 13
7. UNITTESTSVS INTEGRATIONTESTS
• Many Django project test suites are comprised mostly of integration tests
• What is a UnitTest?
• UnitTests cover a small “unit” of code
• Ideally, these units include as few branches as possible
• What is an IntegrationTest?
• IntegrationTests test the contracts between your “units”
Monday, September 2, 13
8. UNITTESTSVS INTEGRATIONTESTS
• Django test client is an integration test
dead giveaway
• The test client covers way more than
you are interested in testing
• URL Routing, Request Middleware,
ORM,Template Rendering, Response
Middleware, etc
Monday, September 2, 13
9. UNITTESTSVS INTEGRATIONTESTS
• A good unit tests covers code that is
limited in functionality/scope
• Ideally, a single method with limited
external calls
Monday, September 2, 13
10. UNITTESTSVS INTEGRATIONTESTS
• Establish a good ratio of unit tests to integration tests. An example may be:
• for each method that contains business logic, there should exist a unit test
• for each page/view/user path of your project, there should exist an integration test
• YMMV
Monday, September 2, 13
12. SET UP CAUTIOUSLY
• Be judicious about how you use setUp/tearDown
• Think like middleware--do I need this for every test in this case?
• One inefficient computation can cripple a large test case
Monday, September 2, 13
14. SET UP CAUTIOUSLY
• Take advantage of setUpClass /
tearDownClass
• Runs once per test case
• Effective for read-only data that
is not altered by tests
• Your data will persist
between tests!
Monday, September 2, 13
17. THE DATABASE IS HOT LAVA
• If you touch it you’ll die
• Not really, but it’s one of slowest things your application will do in a unit test
• Work with read-only, non persisted data
• use in-memory model instances
Monday, September 2, 13
18. THE DATABASE IS HOT LAVA
• Avoid fixtures. Fixtures add lots of database machinery to tests
• Loaded/purged between each test in a case
• Fixtures don’t adapt with your data model
• Schema changes will often result in test failures
• Not much need for django.test.TestCase
• When you do write: in-memory database (SQLite)
Monday, September 2, 13
21. FAKE IT ‘TILYOU MAKE IT WITH MOCK
• Mock is a library for creating programmable stub objects
• Mock objects can be configured to emulate other objects/structures
• Configure specific behavior for just for testing
• Gets rid of unnecessary overhead
Monday, September 2, 13
22. FAKE IT ‘TILYOU MAKE IT WITH MOCK
• Use mock to emulate model instances
• Set the attributes you need for testing
directly
• Use the spec argument to give
guidelines
• No Model/ORM overhead
Monday, September 2, 13
23. FAKE IT ‘TILYOU MAKE IT WITH MOCK
• Use mock.patch to focus your tests
• Patch in configurable mock objects to
sys.modules
• Alter the behavior of code imported
elsewhere
• Eliminate branches you are not
interested in testing
Monday, September 2, 13
25. FAKE IT ‘TILYOU MAKE IT WITH MOCK
• Use mock in more complex situations
• mock.patch.multiple decorator lets you patch multiple module references
simultaneously
• Track the way objects are used
• Mock.assert_has_calls, Mock.assert_called_with
• many, many more: http://www.voidspace.org.uk/python/mock/
Monday, September 2, 13
27. IT’S OKAYTO ENGINEER WHENTESTING
• Don’t be afraid to invest engineering effort into your test suite
• Your tests are Python code--take advantage of it!
• Write tools to help you test
• Leverage 3rd party tools (mock, django-nose)
• Decorators, custom test runners
• If you can’t test the code efficiently, refactor the code!
Monday, September 2, 13
29. HOW SLOWTESTINGYIELDED
EFFECTIVETESTING
• Started out working towards speed
• In order to write fast tests, we had to rethink how we tested
• Developed an efficient test philosophy
• Resulted in much more effective tests, and ultimately better code
Monday, September 2, 13