E-raamat: Test-Driven Development with Python: Obey the Testing Goat: Using Django, Selenium, and JavaScript

  • Formaat: 604 pages
  • Ilmumisaeg: 02-Aug-2017
  • Kirjastus: O'Reilly Media, Inc, USA
  • ISBN-13: 9781491958650
Teised raamatud teemal:
  • Formaat - EPUB+DRM
  • Hind: 39,05 EUR*
  • Lisa soovinimekirja
  • Lisa ostukorvi
  • * hind on lõplik, st. muud allahindlused enam ei rakendu
  • See e-raamat on mõeldud ainult isiklikuks kasutamiseks.
  • Formaat: 604 pages
  • Ilmumisaeg: 02-Aug-2017
  • Kirjastus: O'Reilly Media, Inc, USA
  • ISBN-13: 9781491958650
Teised raamatud teemal:

DRM piirangud

  • Kopeerimine (copy/paste):

    ei ole lubatud

  • Printimine:

    ei ole lubatud

  • Kasutamine:

    E-raamatu lugemiseks on vaja luua Adobe ID ning laadida arvutisse Adobe Digital Editions. Lähemalt siit. E-raamatut saab lugeda ning alla laadida kuni 6'de seadmesse.
    E-raamatut ei saa lugeda Amazon Kindle's. Ülejäänud meie e-poes pakutavad e-lugerid võimaldavad lugeda Adobe ID-ga kaitstud e-raamatuid.

By taking you through the development of a real web application from beginning to end, the second edition of this hands-on guide demonstrates the practical advantages of test-driven development (TDD) with Python. 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, you'll learn the basics of Django, Selenium, Git, jQuery, and Mock, along with current web development techniques. If you're ready to take your Python skills to the next level, this book-updated for Python 3.6-clearly demonstrates how TDD encourages simple designs and inspires confidence. Dive into the TDD workflow, including the unit test/code cycle and refactoring Use unit tests for classes and functions, and functional tests for user interactions within the browser Learn when and how to use mock objects, and the pros and cons of isolated vs. integrated tests Test and automate your deployments with a staging server Apply tests to the third-party plugins you integrate into your site Run tests automatically by using a Continuous Integration environment Use TDD to build a REST API with a front-end Ajax interface
Preface xv
Prerequisites and Assumptions xxi
Companion Video xxxi
Acknowledgments xxxiii
Part I. The Basics of TDD and Django
1 Getting Django Set Up Using a Functional Test
3(10)
Obey the Testing Goat! Do Nothing Until You Have a Test
3(3)
Getting Django Up and Running
6(2)
Starting a Git Repository
8(5)
2 Extending Our Functional Test Using the unittest Module
13(8)
Using a Functional Test to Scope Out a Minimum Viable App
14(2)
The Python Standard Library's unittest Module
16(3)
Commit
19(2)
3 Testing a Simple Home Page with Unit Tests
21(16)
Our First Django App, and Our First Unit Test
22(1)
Unit Tests, and How They Differ from Functional Tests
22(1)
Unit Testing in Django
23(2)
Django's MVC, URLs, and View Functions
25(1)
At Last! We Actually Write Some Application Code!
26(2)
urls.py
28(2)
Unit Testing a View
30(7)
The Unit-Test/Code Cycle
32(5)
4 What Are We Doing with All These Tests? (And, Refactoring)
37(18)
Programming Is Like Pulling a Bucket of Water Up from a Well
38(2)
Using Selenium to Test User Interactions
40(3)
The "Don't Test Constants" Rule, and Templates to the Rescue
43(6)
Refactoring to Use a Template
43(4)
The Django Test Client
47(2)
On Refactoring
49(1)
A Little More of Our Front Page
50(2)
Recap: The TDD Process
52(3)
5 Saving User Input: Testing the Database
55(28)
Wiring Up Our Form to Send a POST Request
55(4)
Processing a POST Request on the Server
59(1)
Passing Python Variables to Be Rendered in the Template
60(4)
Three Strikes and Refactor
64(2)
The Django ORM and Our First Model
66(4)
Our First Database Migration
68(1)
The Test Gets Surprisingly Far
69(1)
A New Field Means a New Migration
69(1)
Saving the POST to the Database
70(4)
Redirect After a POST
74(1)
Better Unit Testing Practice: Each Test Should Test One Thing
75(1)
Rendering Items in the Template
75(3)
Creating Our Production Database with migrate
78(2)
Recap
80(3)
6 Improving Functional Tests: Ensuring Isolation and Removing Voodoo Sleeps
83(12)
Ensuring Test Isolation in Functional Tests
83(5)
Running Just the Unit Tests
87(1)
Aside: Upgrading Selenium and Geckodriver
88(1)
On Implicit and Explicit Waits, and Voodoo time.sleeps
89(6)
7 Working Incrementally
95(40)
Small Design When Necessary
95(2)
Not Big Design Up Front
95(1)
YAGNI!
96(1)
REST (ish)
96(1)
Implementing the New Design Incrementally Using TDD
97(2)
Ensuring We Have a Regression Test
99(2)
Iterating Towards the New Design
101(2)
Taking a First, Self-Contained Step: One New URL
103(3)
A New URL
103(1)
A New View Function
104(2)
Green? Refactor
106(1)
Another Small Step: A Separate Template for Viewing Lists
107(2)
A Third Small Step: A URL for Adding List Items
109(4)
A Test Class for New List Creation
109(1)
A URL and View for New List Creation
110(1)
Removing Now-Redundant Code and Tests
111(1)
A Regression! Pointing Our Forms at the New URL
112(1)
Biting the Bullet: Adjusting Our Models
113(6)
A Foreign Key Relationship
115(2)
Adjusting the Rest of the World to Our New Models
117(2)
Each List Should Have Its Own URL
119(4)
Capturing Parameters from URLs
120(1)
Adjusting new_list to the New World
121(2)
The Functional Tests Detect Another Regression
123(1)
One More View to Handle Adding Items to an Existing List
124(5)
Beware of Greedy Regular Expressions!
125(1)
The Last New URL
125(1)
The Last New View
126(1)
Testing the Response Context Objects Directly
127(2)
A Final Refactor Using URL includes
129(6)
Part II. Web Development Sine Qua Nons
8 Prettification: Layout and Styling, and What to Test About It
135(20)
What to Functionally Test About Layout and Style
135(4)
Prettification: Using a CSS Framework
139(2)
Django Template Inheritance
141(1)
Integrating Bootstrap
142(2)
Rows and Columns
143(1)
Static Files in Django
144(2)
Switching to StaticLiveServerTestCase
145(1)
Using Bootstrap Components to Improve the Look of the Site
146(1)
Jumbotron!
146(1)
Large Inputs
147(1)
Table Styling
147(1)
Using Our Own CSS
147(2)
What We Glossed Over: collectstatic and Other Static Directories
149(3)
A Few Things That Didn't Make It
152(3)
9 Testing Deployment Using a Staging Site
155(20)
TDD and the Danger Areas of Deployment
156(1)
As Always, Start with a Test
157(3)
Getting a Domain Name
160(1)
Manually Provisioning a Server to Host Our Site
160(4)
Choosing Where to Host Our Site
160(1)
Spinning Up a Server
161(1)
User Accounts, SSH, and Privileges
162(1)
Installing Nginx
162(1)
Installing Python 3.6
163(1)
Configuring Domains for Staging and Live
163(1)
Using the FT to Confirm the Domain Works and Nginx Is Running
164(1)
Deploying Our Code Manually
164(9)
Adjusting the Database Location
165(2)
Creating a Virtualenv Manually, and Using requirements.txt
167(1)
Simple Nginx Configuration
168(3)
Creating the Database with migrate
171(2)
Success! Our Hack Deployment Works
173(2)
10 Getting to a Production-Ready Deployment
175(12)
Switching to Gunicorn
175(2)
Getting Nginx to Serve Static Files
177(1)
Switching to Using Unix Sockets
177(1)
Switching DEBUG to False and Setting ALLOWED_HOSTS
178(1)
Using Systemd to Make Sure Gunicorn Starts on Boot
179(2)
Saving Our Changes: Adding Gunicorn to Our requirements.txt
180(1)
Thinking About Automating
181(3)
Saving Templates for Our Provisioning Config Files
181(3)
Saving Our Progress
184(3)
11 Automating Deployment with Fabric
187(14)
Breakdown of a Fabric Script for Our Deployment
188(5)
Creating the Directory Structure
189(1)
Pulling Down Our Source Code with Git
189(1)
Updating settings.py
190(2)
Updating the Virtualenv
192(1)
Migrating the Database If Necessary
192(1)
Trying It Out
193(6)
Deploying to Live
194(2)
Nginx and Gunicorn Config Using sed
196(3)
Git Tag the Release
199(1)
Further Reading
199(2)
12 Splitting Our Tests into Multiple Files, and a Generic Wait Helper
201(16)
Start on a Validation FT: Preventing Blank Items
201(6)
Skipping a Test
202(1)
Splitting Functional Tests Out into Many Files
203(3)
Running a Single Test File
206(1)
A New Functional Test Tool: A Generic Explicit Wait Helper
207(4)
Finishing Off the FT
211(2)
Refactoring Unit Tests into Several Files
213(4)
13 Validation at the Database Layer
217(18)
Model-Layer Validation
218(2)
The self.assertRaises Context Manager
218(1)
A Django Quirk: Model Save Doesn't Run Validation
219(1)
Surfacing Model Validation Errors in the View
220(5)
Checking That Invalid Input Isn't Saved to the Database
223(2)
Django Pattern: Processing POST Requests in the Same View as Renders the Form
225(6)
Refactor: Transferring the new_item Functionality into view_list
226(3)
Enforcing Model Validation in view_list
229(2)
Refactor: Removing Hardcoded URLs
231(4)
The {% url %} Template Tag
231(1)
Using get_absolute_url for Redirects
232(3)
14 A Simple Form
235(24)
Moving Validation Logic into a Form
235(6)
Exploring the Forms API with a Unit Test
236(2)
Switching to a Django ModelForm
238(1)
Testing and Customising Form Validation
239(2)
Using the Form in Our Views
241(4)
Using the Form in a View with a GET Request
241(1)
A Big Find and Replace
242(3)
Using the Form in a View That Takes POST Requests
245(3)
Adapting the Unit Tests for the new_list View
245(1)
Using the Form in the View
246(1)
Using the Form to Display Errors in the Template
247(1)
Using the Form in the Other View
248(5)
A Helper Method for Several Short Tests
248(3)
An Unexpected Benefit: Free Client-Side Validation from HTML5
251(2)
A Pat on the Back
253(1)
But Have We Wasted a Lot of Time?
254(1)
Using the Form's Own Save Method
254(5)
15 More Advanced Forms
259(18)
Another FT for Duplicate Items
259(9)
Preventing Duplicates at the Model Layer
260(3)
A Little Digression on Queryset Ordering and String Representations
263(2)
Rewriting the Old Model Test
265(2)
Some Integrity Errors Do Show Up on Save
267(1)
Experimenting with Duplicate Item Validation at the Views Layer
268(1)
A More Complex Form to Handle Uniqueness Validation
269(2)
Using the Existing List Item Form in the List View
271(2)
Wrapping Up: What We've Learned About Testing Django
273(4)
16 Dipping Our Toes, Very Tentatively, into JavaScript
277(18)
Starting with an FT
277(2)
Setting Up a Basic JavaScript Test Runner
279(2)
Using jQuery and the Fixtures Div
281(4)
Building a JavaScript Unit Test for Our Desired Functionality
285(2)
Fixtures, Execution Order, and Global State: Key Challenges of JS Testing
287(4)
console.log for Debug Printing
287(2)
Using an Initialize Function for More Control Over Execution Time
289(2)
Columbo Says: Onload Boilerplate and Namespacing
291(1)
JavaScript Testing in the TDD Cycle
292(1)
A Few Things That Didn't Make It
293(2)
17 Deploying Our New Code
295(6)
Staging Deploy
295(1)
Live Deploy
296(1)
What to Do If You See a Database Error
296(1)
Wrap-Up: git tag the New Release
296(5)
Part III. More Advanced Topics in Testing
18 User Authentication, Spiking, and De-Spiking
301(22)
Passwordless Auth
302(1)
Exploratory Coding, aka "Spiking"
302(11)
Starting a Branch for the Spike
303(1)
Frontend Log in UI
303(1)
Sending Emails from Django
304(2)
Using Environment Variables to Avoid Secrets in Source Code
306(1)
Storing Tokens in the Database
307(1)
Custom Authentication Models
307(2)
Finishing the Custom Django Auth
309(4)
De-spiking
313(3)
Reverting Our Spiked Code
315(1)
A Minimal Custom User Model
316(4)
Tests as Documentation
319(1)
A Token Model to Link Emails with a Unique ID
320(3)
19 Using Mocks to Test External Dependencies or Reduce Duplication
323(36)
Before We Start: Getting the Basic Plumbing In
323(1)
Mocking Manually, aka Monkeypatching
324(4)
The Python Mock Library
328(9)
Using unittest.patch
328(3)
Getting the FT a Little Further Along
331(1)
Testing the Django Messages Framework
331(2)
Adding Messages to Our HTML
333(1)
Starting on the Login URL
334(1)
Checking That We Send the User a Link with a Token
335(2)
De-spiking Our Custom Authentication Backend
337(7)
1 if = 1 More Test
338(3)
The get_user Method
341(2)
Using Our Auth Backend in the Login View
343(1)
An Alternative Reason to Use Mocks: Reducing Duplication
344(7)
Using mock.return_value
347(2)
Patching at the Class Level
349(2)
The Moment of Truth: Will the FT Pass?
351(2)
It Works in Theory! Does It Work in Practice?
353(1)
Finishing Off Our FT, Testing Logout
354(5)
20 Test Fixtures and a Decorator for Explicit Waits
359(10)
Skipping the Login Process by Pre-creating a Session
360(4)
Checking That It Works
362(2)
Our Final Explicit Wait Helper: A Wait Decorator
364(5)
21 Server-Side Debugging
369(16)
The Proof Is in the Pudding: Using Staging to Catch Final Bugs
369(3)
Setting Up Logging
370(2)
Setting Secret Environment Variables on the Server
372(1)
Adapting Our FT to Be Able to Test Real Emails via POP3
372(4)
Managing the Test Database on Staging
376(6)
A Django Management Command to Create Sessions
376(2)
Getting the FT to Run the Management Command on the Server
378(1)
Using Fabric Directly from Python
379(1)
Recap: Creating Sessions Locally Versus Staging
380(2)
Baking In Our Logging Code
382(1)
Wrap-Up
382(3)
22 Finishing "My Lists": Outside-In TDD
385(16)
The Alternative: "Inside-Out"
385(1)
Why Prefer "Outside-In"?
386(1)
The FT for "My Lists"
386(3)
The Outside Layer: Presentation and Templates
389(1)
Moving Down One Layer to View Functions (the Controller)
390(1)
Another Pass, Outside-In
391(3)
A Quick Restructure of the Template Inheritance Hierarchy
391(1)
Designing Our API Using the Template
392(1)
Moving Down to the Next Layer: What the View Passes to the Template
393(1)
The Next "Requirement" from the Views Layer: New Lists Should Record Owner
394(1)
A Decision Point: Whether to Proceed to the Next Layer with a Failing Test
395(1)
Moving Down to the Model Layer
396(5)
Final Step: Feeding Through the .name API from the Template
398(3)
23 Test Isolation, and "Listening to Your Tests"
401(32)
Revisiting Our Decision Point: The Views Layer Depends on Unwritten Models Code
401(1)
A First Attempt at Using Mocks for Isolation
402(4)
Using Mock side_effects to Check the Sequence of Events
404(2)
Listen to Your Tests: Ugly Tests Signal a Need to Refactor
406(1)
Rewriting Our Tests for the View to Be Fully Isolated
406(6)
Keep the Old Integrated Test Suite Around as a Sanity Check
406(1)
A New Test Suite with Full Isolation
407(1)
Thinking in Terms of Collaborators
407(5)
Moving Down to the Forms Layer
412(4)
Keep Listening to Your Tests: Removing ORM Code from Our Application
413(3)
Finally, Moving Down to the Models Layer
416(4)
Back to Views
419(1)
The Moment of Truth (and the Risks of Mocking)
420(1)
Thinking of Interactions Between Layers as "Contracts"
421(4)
Identifying Implicit Contracts
422(2)
Fixing the Oversight
424(1)
One More Test
425(1)
Tidy Up: What to Keep from Our Integrated Test Suite
426(3)
Removing Redundant Code at the Forms Layer
426(1)
Removing the Old Implementation of the View
427(2)
Removing Redundant Code at the Forms Layer
429(1)
Conclusions: When to Write Isolated Versus Integrated Tests
429(4)
Let Complexity Be Your Guide
430(1)
Should You Do Both?
431(1)
Onwards!
431(2)
24 Continuous Integration (CI)
433(20)
Installing Jenkins
433(1)
Configuring Jenkins
434(4)
Initial Unlock
435(1)
Suggested Plugins for Now
435(1)
Configuring the Admin User
435(2)
Adding Plugins
437(1)
Telling Jenkins Where to Find Python 3 and Xvfb
437(1)
Finishing Off with HTTPS
438(1)
Setting Up Our Project
438(1)
First Build!
439(2)
Setting Up a Virtual Display So the FTs Can Run Headless
441(2)
Taking Screenshots
443(4)
If in Doubt, Try Bumping the Timeout!
447(1)
Running Our QUnit JavaScript Tests in Jenkins with PhantomJS
448(3)
Installing node
448(1)
Adding the Build Steps to Jenkins
449(2)
More Things to Do with a CI Server
451(2)
25 The Token Social Bit, the Page Pattern, and an Exercise for the Reader
453(10)
An FT with Multiple Users, and addCleanup
453(2)
The Page Pattern
455(3)
Extend the FT to a Second User, and the "My Lists" Page
458(1)
An Exercise for the Reader
459(4)
26 Fast Tests, Slow Tests, and Hot Lava
463(10)
Thesis: Unit Tests Are Superfast and Good Besides That
464(2)
Faster Tests Mean Faster Development
465(1)
The Holy Flow State
465(1)
Slow Tests Don't Get Run as Often, Which Causes Bad Code
465(1)
We're Fine Now, but Integrated Tests Get Slower Over Time
465(1)
Don't Take It from Me
466(1)
And Unit Tests Drive Good Design
466(1)
The Problems with "Pure" Unit Tests
466(1)
Isolated Tests Can Be Harder to Read and Write
466(1)
Isolated Tests Don't Automatically Test Integration
466(1)
Unit Tests Seldom Catch Unexpected Bugs
466(1)
Mocky Tests Can Become Closely Tied to Implementation
467(1)
But All These Problems Can Be Overcome
467(1)
Synthesis: What Do We Want from Our Tests, Anyway?
467(2)
Correctness
467(1)
Clean, Maintainable Code
467(1)
Productive Workflow
468(1)
Evaluate Your Tests Against the Benefits You Want from Them
468(1)
Architectural Solutions
469(1)
Ports and Adapters/Hexagonal/Clean Architecture
469(1)
Functional Core, Imperative Shell
470(1)
Conclusion
470(3)
Further Reading
471(2)
Obey the Testing Goat! 473(92)
A PythonAnywhere
475(4)
B Django Class-Based Views
479(12)
C Provisioning with Ansible
491(6)
D Testing Database Migrations
497(6)
E Behaviour-Driven Development (BDD)
503(16)
F Building a REST API: JSON, Ajax, and Mocking with JavaScript
519(22)
G Django-Rest-Framework
541(12)
H Cheat Sheet
553(4)
I What to Do Next
557(4)
J Source Code Examples
561(4)
Bibliography 565(2)
Index 567
After an idyllic childhood spent playing with BASIC on French 8-bit computers like the Thomson T-07 whose keys go "boop" when you press them, Harry went on to study Economics and Philosophy at Cambridge University. He then spent a few years being deeply unhappy as a management consultant. Soon he rediscovered his true geek nature, and was lucky enough to fall in with a bunch of XP fanatics, working on the pioneering but sadly defunct Resolver One spreadsheet. He now works at PythonAnywhere LLP, and spreads the gospel of TDD world-wide at talks, workshops and conferences, with all the passion and enthusiasm of a recent convert.