Log In
Or create an account ->
Imperial Library
Home
About
News
Upload
Forum
Help
Login/SignUp
Index
Test-Driven Web Development with Python
Preface
Why I wrote a book about Test-Driven Development
Aims of this book
Outline
Some pre-requisites
Python 3 & programming
How HTML works
Required software installations:
Required Python modules:
Conventions Used in This Book
Contacting O’Reilly
1. Getting Django set up using a Functional Test
Obey the Testing Goat! Do nothing until you have a test
Getting Django up and running
Starting a Git repository
2. Extending our Functional Test using the unittest module
Using the Functional Test to scope out a minimum viable app
The Python standard library’s unittest module
Implicitly wait
Commit
3. Testing a simple home page with unit tests
Our first Django app, and our first unit test
Unit tests, and how they differ from Functional tests
Unit testing in Django
Django’s MVC, URLs and view functions
At last! We actually write some application code!
Reading tracebacks
urls.py
Unit testing a view
The unit test / code cycle
4. What are we doing with all these tests?
Programming is like pulling a bucket of water up from a well
On the merits of trivial tests for trivial functions
Using Selenium to test user interactions
The “Don’t test constants” rule, and templates to the rescue
On refactoring
A little more of our front page
Recap: the TDD process
5. Saving user input
Wiring up our form to send a POST request
Processing a POST request on the server
3 strikes and refactor
The Django ORM & our first model
Saving the POST to the database
Redirect after a POST
Better unit testing practice: each test should test one thing
Rendering items in the template
Creating our production database with syncdb
6. Getting to the minimum viable site
Ensuring test isolation in functional tests
Running just the unit tests
Small Design When Necessary
YAGNI!
REST
Implementing the new design using TDD
Iterating towards the new design
Testing views, templates and URLs together with the Django Test Client
A URL and view for adding list items
Adjusting our models
Each list should have its own URL
One more view to handle adding items to an existing list
A final refactor using URL includes
7. Prettification: layout and styling, and what to test about it
What to functionally test about layout and style
Prettification: Using a CSS framework
Django template inheritance
Integrating Bootstrap
Static files in Django
What we skipped over: collectstatic and other static directories
8. Testing deployment using a staging site
TDD and the Danger Areas of deployment
As always, start with a test
Getting a domain name
Manually provisioning a server to host our site
Choosing where to host our site
Spinning up a server
User accounts, SSH and privileges
Installing Nginx
Configuring domains for staging and live
Deploying our code manually
Adjusting the database location
Creating a virtualenv
Simple nginx configuration
Creating the database with syncdb
Switching to Gunicorn
Getting Nginx to serve static files
Switching to using Unix sockets
Switching DEBUG to False and setting ALLOWED_HOSTS
Using upstart to make sure gunicorn starts on boot
Saving our changes: adding gunicorn to our requirements.txt
Automating:
Automating deployment with fabric
Git tag the release
Recap:
Further reading:
Todos
9. Input validation and test organisation
Validation FT: preventing blank items
Skipping a test
Splitting functional tests out into many files
Running a single test file
Fleshing out the FT
Using model-layer validation
Refactoring unit tests into several files
Unit testing model validation and the self.assertRaises context manager
Overriding the save method on a model to ensure validation
Handling model validation errors in the view:
Django pattern: processing POST request in the same view as renders the form
Refactor: Removing hard-coded URLs
The {% url %} template tag
Using get_absolute_url for redirects
10. A simple form
Moving validation logic into a form
Switching to a Django ModelForm
Testing and customising form validation
Using the form in our views
Using the form in a view with a GET request
A big find & replace
Using the form in a view that takes POST requests
Using the form in the final view
A helper method for several short tests
Using the form’s own save method
The request.POST or None trick
11. More advanced Forms
Another FT for duplicate items
Preventing duplicates at the model layer
A little digression on Queryset ordering and string representations
Handling validation at the views layer
A more complex form to handle uniqueness validation
Using the existing lists item form in the list view
Recap: what to test in views
12. Database migrations
South vs Django migrations
Creating an initial migration to match the current live state
Migrations: like a VCS for your database
Wrap-up: remove fake migration and git tag
On testing database migrations
Don’t test third party code
Do test migrations for speed
Be extremely careful if using a dump of production data
13. Dipping our toes, very tentatively, into JavaScript
Starting with an FT
Setting up a basic JavaScript test runner
Using jquery and the fixtures div
Building a JavaScript unit test for our desired functionality
Columbo says: onload boilerplate and namespacing
14. User authentication, integrating 3rd party plugins, and Mocking with JavaScript
Mozilla Persona (BrowserID)
Exploratory coding, aka “spiking”
De-Spiking
A common Selenium technique: waiting for
Reverting our spiked code
Javascript unit tests involving external components. Our first Mocks!
Why Mock?
Namespacing
A simple mock to unit tests our initialize function
More advanced mocking
Using a spy to check we call the API correctly
Checking call arguments
Qunit setup and teardown, testing Ajax
Logout
More nested callbacks! Testing asynchronous code
15. Server-side authentication and mocking in Python
Mocking in Python
De-spiking our custom authentication back-end: mocking out an internet request
1 if = 1 more test
patching at the Class level
Beware of Mocks in boolean comparisons
Creating a user if necessary
Tests the get_user method by mocking the Django ORM
Testing exception handling
A minimal custom user model
Tests as documentation
A slight disappointment
Fixing our cheat
The moment of truth: will the FT pass?
Finishing off our FT, testing logout
16. Test fixtures and server-side debugging
Skipping the login process by pre-creating a session
Checking it works
The proof is in the pudding: using staging to catch final bugs
Staging finds an unexpected bug (that’s what it’s for!)
Setting up logging
Fixing the Persona bug
Managing the test database on staging
A Django management command to create sessions
An additional hop via subprocess
17. Finishing “my lists”: Outside-In TDD
The FT for “My Lists”
Outside-in TDD
The outside layer: presentation & templates
Moving down one layer to view functions (the controller)
Another pass, outside-in
A quick re-structure of the template inheritance hierarchy
Designing our API using the template
Moving down to the next layer: what the view passes to the template
The next “requirement” from the views layer
Moving down again: to the model layer
Final step: feeding through the .name API from the template
A. PythonAnywhere
Running Firefox Selenium sessions with pyVirtualDisplay
Setting up Django as a PythonAnywhere web app
Cleaning up /tmp
Screenshots
B. Django Class-Based Views
Class-based generic views
The home page as a FormView
Using form_valid to customise a CreateView
A more complex view to handle both viewing and adding to a list
Compare old and new
Best practices for unit testing CBGVs?
Take-home: having multiple, isolated view test with single assertions helps
C. Provisioning with Ansible
Installing system packages and nginx
Configuring gunicorn, and using handlers to restart services
About the Author
Copyright
← Prev
Back
Next →
← Prev
Back
Next →