100% found this document useful (1 vote)
58 views

Test Driven Development with Python Obey the Testing Goat Using Django Selenium and JavaScript 2nd Edition Harry J. W. Percival 2024 Scribd Download

Django

Uploaded by

gjetannwafor
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
58 views

Test Driven Development with Python Obey the Testing Goat Using Django Selenium and JavaScript 2nd Edition Harry J. W. Percival 2024 Scribd Download

Django

Uploaded by

gjetannwafor
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 65

Experience Seamless Full Ebook Downloads for Every Genre at textbookfull.

com

Test Driven Development with Python Obey the


Testing Goat Using Django Selenium and JavaScript
2nd Edition Harry J. W. Percival

https://textbookfull.com/product/test-driven-development-
with-python-obey-the-testing-goat-using-django-selenium-and-
javascript-2nd-edition-harry-j-w-percival/

OR CLICK BUTTON

DOWNLOAD NOW

Explore and download more ebook at https://textbookfull.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

Python Testing Cookbook Easy solutions to test your Python


projects using test driven development and Selenium 2nd
Edition Greg L. Turnquist & Bhaskar N. Das
https://textbookfull.com/product/python-testing-cookbook-easy-
solutions-to-test-your-python-projects-using-test-driven-development-
and-selenium-2nd-edition-greg-l-turnquist-bhaskar-n-das/
textboxfull.com

Python Testing with Selenium: Learn to Implement Different


Testing Techniques Using the Selenium WebDriver Sujay
Raghavendra
https://textbookfull.com/product/python-testing-with-selenium-learn-
to-implement-different-testing-techniques-using-the-selenium-
webdriver-sujay-raghavendra/
textboxfull.com

Tango With Django: A beginner’s Guide to Web Development


With Python / Django 1.9 1st Edition Leif Azzopardi

https://textbookfull.com/product/tango-with-django-a-beginners-guide-
to-web-development-with-python-django-1-9-1st-edition-leif-azzopardi/

textboxfull.com

Test Driven JavaScript Development 1st Edition Gupta Ravi


Kumar Prajapati Hetal Singh Harmeet

https://textbookfull.com/product/test-driven-javascript-
development-1st-edition-gupta-ravi-kumar-prajapati-hetal-singh-
harmeet/
textboxfull.com
Thoughtful machine learning with Python a test driven
approach First Edition Kirk

https://textbookfull.com/product/thoughtful-machine-learning-with-
python-a-test-driven-approach-first-edition-kirk/

textboxfull.com

iOS Test Driven Development by Tutorials First Edition


Learn Real World Test Driven Development Joshua Greene

https://textbookfull.com/product/ios-test-driven-development-by-
tutorials-first-edition-learn-real-world-test-driven-development-
joshua-greene/
textboxfull.com

Beginning Django: Web Application Development and


Deployment with Python 1st Edition Daniel Rubio (Auth.)

https://textbookfull.com/product/beginning-django-web-application-
development-and-deployment-with-python-1st-edition-daniel-rubio-auth/

textboxfull.com

Django For Beginners: Build Websites With Python And


Django William S. Vincent

https://textbookfull.com/product/django-for-beginners-build-websites-
with-python-and-django-william-s-vincent/

textboxfull.com

Thoughtful Machine Learning with Python A Test Driven


Approach 1st Edition Matthew Kirk

https://textbookfull.com/product/thoughtful-machine-learning-with-
python-a-test-driven-approach-1st-edition-matthew-kirk/

textboxfull.com
2n
d
Ed
iti
on
Test-Driven
Development
with Python
OBEY THE TESTING GOAT:
USING DJANGO, SELENIUM & JAVASCRIPT

Fewer Bugs and Less Stress with Selenium,


Django, and JavaScript

Harry J.W. Percival


WOW! eBook
www.wowebook.org
WOW! eBook
www.wowebook.org
Praise for Test-Driven Development with Python

In this book, Harry takes us on an adventure of discovery with Python and testing.
It’s an excellent book, fun to read and full of vital information. It has my highest
recommendations for anyone interested in testing with Python, learning Django, or
wanting to use Selenium. Testing is essential for developer sanity and it’s a notoriously
difficult field, full of trade-offs. Harry does a fantastic job of holding our attention whilst
exploring real-world testing practices.
—Michael Foord, Python Core Developer and Maintainer
of unittest

This book is far more than an introduction to test-driven development—it’s a complete


best-practices crash course, from start to finish, into modern web application
development with Python. Every web developer needs this book.
—Kenneth Reitz, Fellow at Python Software Foundation

Harry’s book is what we wish existed when we were learning Django. At a pace that’s
achievable and yet delightfully challenging, it provides excellent instruction for Django
and various test practices. The material on Selenium alone makes the book worth
purchasing, but there’s so much more!
—Daniel and Audrey Roy Greenfeld, authors of Two Scoops of
Django (Two Scoops Press)

WOW! eBook
www.wowebook.org
WOW! eBook
www.wowebook.org
SECOND EDITION

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

Harry J.W. Percival

Beijing Boston Farnham Sebastopol Tokyo

WOW! eBook
www.wowebook.org
Test-Driven Development with Python
by Harry J.W. Percival
Copyright © 2017 Harry Percival. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are
also available for most titles (http://oreilly.com/safari). For more information, contact our corporate/insti‐
tutional sales department: 800-998-9938 or [email protected].

Editor: Nan Barber Indexer: Judith McConville


Production Editor: Kristen Brown Interior Designer: David Futato
Copyeditor: Kim Cofer Cover Designer: Karen Montgomery
Proofreader: Rachel Monaghan Illustrator: Rebecca Demarest

August 2017: Second Edition

Revision History for the Second Edition


2017-08-02: First Release

See http://oreilly.com/catalog/errata.csp?isbn=9781491958704 for release details.

The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Test-Driven Development with Python,
the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.
While the publisher and the author have used good faith efforts to ensure that the information and
instructions contained in this work are accurate, the publisher and the author disclaim all responsibility
for errors or omissions, including without limitation responsibility for damages resulting from the use of
or reliance on this work. Use of the information and instructions contained in this work is at your own
risk. If any code samples or other technology this work contains or describes is subject to open source
licenses or the intellectual property rights of others, it is your responsibility to ensure that your use
thereof complies with such licenses and/or rights.

978-1-491-95870-4
[LSI]

WOW! eBook
www.wowebook.org
Table of Contents

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
Obey the Testing Goat! Do Nothing Until You Have a Test 3
Getting Django Up and Running 6
Starting a Git Repository 8

2. Extending Our Functional Test Using the unittest Module. . . . . . . . . . . . . . . . . . . . . . . 13


Using a Functional Test to Scope Out a Minimum Viable App 14
The Python Standard Library’s unittest Module 16
Commit 19

3. Testing a Simple Home Page with Unit Tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21


Our First Django App, and Our First Unit Test 22
Unit Tests, and How They Differ from Functional Tests 22
Unit Testing in Django 23
Django’s MVC, URLs, and View Functions 24
At Last! We Actually Write Some Application Code! 26
urls.py 28

WOW! eBook
www.wowebook.org
Unit Testing a View 30
The Unit-Test/Code Cycle 32

4. What Are We Doing with All These Tests? (And, Refactoring). . . . . . . . . . . . . . . . . . . . . 37


Programming Is Like Pulling a Bucket of Water Up from a Well 38
Using Selenium to Test User Interactions 40
The “Don’t Test Constants” Rule, and Templates to the Rescue 43
Refactoring to Use a Template 43
The Django Test Client 47
On Refactoring 49
A Little More of Our Front Page 50
Recap: The TDD Process 52

5. Saving User Input: Testing the Database. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55


Wiring Up Our Form to Send a POST Request 55
Processing a POST Request on the Server 59
Passing Python Variables to Be Rendered in the Template 60
Three Strikes and Refactor 64
The Django ORM and Our First Model 66
Our First Database Migration 68
The Test Gets Surprisingly Far 68
A New Field Means a New Migration 69
Saving the POST to the Database 70
Redirect After a POST 73
Better Unit Testing Practice: Each Test Should Test One Thing 74
Rendering Items in the Template 75
Creating Our Production Database with migrate 78
Recap 80

6. Improving Functional Tests: Ensuring Isolation and Removing Voodoo Sleeps. . . . . . 83


Ensuring Test Isolation in Functional Tests 83
Running Just the Unit Tests 87
Aside: Upgrading Selenium and Geckodriver 88
On Implicit and Explicit Waits, and Voodoo time.sleeps 89

7. Working Incrementally. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Small Design When Necessary 95
Not Big Design Up Front 95
YAGNI! 96
REST (ish) 96
Implementing the New Design Incrementally Using TDD 97
Ensuring We Have a Regression Test 99

vi | Table of Contents

WOW! eBook
www.wowebook.org
Iterating Towards the New Design 101
Taking a First, Self-Contained Step: One New URL 103
A New URL 103
A New View Function 104
Green? Refactor 106
Another Small Step: A Separate Template for Viewing Lists 107
A Third Small Step: A URL for Adding List Items 109
A Test Class for New List Creation 109
A URL and View for New List Creation 110
Removing Now-Redundant Code and Tests 111
A Regression! Pointing Our Forms at the New URL 112
Biting the Bullet: Adjusting Our Models 113
A Foreign Key Relationship 115
Adjusting the Rest of the World to Our New Models 117
Each List Should Have Its Own URL 119
Capturing Parameters from URLs 120
Adjusting new_list to the New World 121
The Functional Tests Detect Another Regression 123
One More View to Handle Adding Items to an Existing List 124
Beware of Greedy Regular Expressions! 125
The Last New URL 125
The Last New View 126
Testing the Response Context Objects Directly 127
A Final Refactor Using URL includes 129

Part II. Web Development Sine Qua Nons


8. Prettification: Layout and Styling, and What to Test About It. . . . . . . . . . . . . . . . . . . 135
What to Functionally Test About Layout and Style 135
Prettification: Using a CSS Framework 139
Django Template Inheritance 141
Integrating Bootstrap 142
Rows and Columns 143
Static Files in Django 144
Switching to StaticLiveServerTestCase 145
Using Bootstrap Components to Improve the Look of the Site 146
Jumbotron! 146
Large Inputs 147
Table Styling 147
Using Our Own CSS 147
What We Glossed Over: collectstatic and Other Static Directories 149

Table of Contents | vii

WOW! eBook
www.wowebook.org
A Few Things That Didn’t Make It 152

9. Testing Deployment Using a Staging Site. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155


TDD and the Danger Areas of Deployment 156
As Always, Start with a Test 157
Getting a Domain Name 160
Manually Provisioning a Server to Host Our Site 160
Choosing Where to Host Our Site 160
Spinning Up a Server 161
User Accounts, SSH, and Privileges 162
Installing Nginx 162
Installing Python 3.6 163
Configuring Domains for Staging and Live 163
Using the FT to Confirm the Domain Works and Nginx Is Running 164
Deploying Our Code Manually 164
Adjusting the Database Location 165
Creating a Virtualenv Manually, and Using requirements.txt 167
Simple Nginx Configuration 168
Creating the Database with migrate 171
Success! Our Hack Deployment Works 173

10. Getting to a Production-Ready Deployment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175


Switching to Gunicorn 175
Getting Nginx to Serve Static Files 177
Switching to Using Unix Sockets 177
Switching DEBUG to False and Setting ALLOWED_HOSTS 178
Using Systemd to Make Sure Gunicorn Starts on Boot 179
Saving Our Changes: Adding Gunicorn to Our requirements.txt 180
Thinking About Automating 181
Saving Templates for Our Provisioning Config Files 181
Saving Our Progress 184

11. Automating Deployment with Fabric. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187


Breakdown of a Fabric Script for Our Deployment 188
Creating the Directory Structure 189
Pulling Down Our Source Code with Git 189
Updating settings.py 190
Updating the Virtualenv 192
Migrating the Database If Necessary 192
Trying It Out 193
Deploying to Live 194
Nginx and Gunicorn Config Using sed 196

viii | Table of Contents

WOW! eBook
www.wowebook.org
Git Tag the Release 199
Further Reading 199

12. Splitting Our Tests into Multiple Files, and a Generic Wait Helper. . . . . . . . . . . . . . . . 201
Start on a Validation FT: Preventing Blank Items 201
Skipping a Test 202
Splitting Functional Tests Out into Many Files 203
Running a Single Test File 206
A New Functional Test Tool: A Generic Explicit Wait Helper 207
Finishing Off the FT 211
Refactoring Unit Tests into Several Files 213

13. Validation at the Database Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217


Model-Layer Validation 218
The self.assertRaises Context Manager 218
A Django Quirk: Model Save Doesn’t Run Validation 219
Surfacing Model Validation Errors in the View 220
Checking That Invalid Input Isn’t Saved to the Database 223
Django Pattern: Processing POST Requests in the Same View as Renders the
Form 225
Refactor: Transferring the new_item Functionality into view_list 226
Enforcing Model Validation in view_list 229
Refactor: Removing Hardcoded URLs 231
The {% url %} Template Tag 231
Using get_absolute_url for Redirects 232

14. A Simple Form. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235


Moving Validation Logic into a Form 235
Exploring the Forms API with a Unit Test 236
Switching to a Django ModelForm 238
Testing and Customising Form Validation 239
Using the Form in Our Views 241
Using the Form in a View with a GET Request 241
A Big Find and Replace 242
Using the Form in a View That Takes POST Requests 245
Adapting the Unit Tests for the new_list View 245
Using the Form in the View 246
Using the Form to Display Errors in the Template 247
Using the Form in the Other View 248
A Helper Method for Several Short Tests 248
An Unexpected Benefit: Free Client-Side Validation from HTML5 251
A Pat on the Back 253

Table of Contents | ix

WOW! eBook
www.wowebook.org
But Have We Wasted a Lot of Time? 254
Using the Form’s Own Save Method 254

15. More Advanced Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259


Another FT for Duplicate Items 259
Preventing Duplicates at the Model Layer 260
A Little Digression on Queryset Ordering and String Representations 263
Rewriting the Old Model Test 265
Some Integrity Errors Do Show Up on Save 267
Experimenting with Duplicate Item Validation at the Views Layer 268
A More Complex Form to Handle Uniqueness Validation 269
Using the Existing List Item Form in the List View 271
Wrapping Up: What We’ve Learned About Testing Django 273

16. Dipping Our Toes, Very Tentatively, into JavaScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . 277


Starting with an FT 277
Setting Up a Basic JavaScript Test Runner 279
Using jQuery and the Fixtures Div 281
Building a JavaScript Unit Test for Our Desired Functionality 285
Fixtures, Execution Order, and Global State: Key Challenges of JS Testing 287
console.log for Debug Printing 287
Using an Initialize Function for More Control Over Execution Time 289
Columbo Says: Onload Boilerplate and Namespacing 291
JavaScript Testing in the TDD Cycle 292
A Few Things That Didn’t Make It 293

17. Deploying Our New Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295


Staging Deploy 295
Live Deploy 296
What to Do If You See a Database Error 296
Wrap-Up: git tag the New Release 296

Part III. More Advanced Topics in Testing


18. User Authentication, Spiking, and De-Spiking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
Passwordless Auth 302
Exploratory Coding, aka “Spiking” 302
Starting a Branch for the Spike 303
Frontend Log in UI 303
Sending Emails from Django 304
Using Environment Variables to Avoid Secrets in Source Code 306

x | Table of Contents

WOW! eBook
www.wowebook.org
Storing Tokens in the Database 307
Custom Authentication Models 307
Finishing the Custom Django Auth 309
De-spiking 313
Reverting Our Spiked Code 315
A Minimal Custom User Model 316
Tests as Documentation 319
A Token Model to Link Emails with a Unique ID 320

19. Using Mocks to Test External Dependencies or Reduce Duplication. . . . . . . . . . . . . . 323


Before We Start: Getting the Basic Plumbing In 323
Mocking Manually, aka Monkeypatching 324
The Python Mock Library 328
Using unittest.patch 328
Getting the FT a Little Further Along 331
Testing the Django Messages Framework 331
Adding Messages to Our HTML 333
Starting on the Login URL 334
Checking That We Send the User a Link with a Token 335
De-spiking Our Custom Authentication Backend 337
1 if = 1 More Test 338
The get_user Method 341
Using Our Auth Backend in the Login View 343
An Alternative Reason to Use Mocks: Reducing Duplication 344
Using mock.return_value 347
Patching at the Class Level 349
The Moment of Truth: Will the FT Pass? 351
It Works in Theory! Does It Work in Practice? 353
Finishing Off Our FT, Testing Logout 354

20. Test Fixtures and a Decorator for Explicit Waits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359


Skipping the Login Process by Pre-creating a Session 360
Checking That It Works 362
Our Final Explicit Wait Helper: A Wait Decorator 364

21. Server-Side Debugging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369


The Proof Is in the Pudding: Using Staging to Catch Final Bugs 369
Setting Up Logging 370
Setting Secret Environment Variables on the Server 372
Adapting Our FT to Be Able to Test Real Emails via POP3 372
Managing the Test Database on Staging 376
A Django Management Command to Create Sessions 376

Table of Contents | xi

WOW! eBook
www.wowebook.org
Getting the FT to Run the Management Command on the Server 378
Using Fabric Directly from Python 379
Recap: Creating Sessions Locally Versus Staging 380
Baking In Our Logging Code 382
Wrap-Up 382

22. Finishing “My Lists”: Outside-In TDD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385


The Alternative: “Inside-Out” 385
Why Prefer “Outside-In”? 386
The FT for “My Lists” 386
The Outside Layer: Presentation and Templates 389
Moving Down One Layer to View Functions (the Controller) 390
Another Pass, Outside-In 391
A Quick Restructure of the Template Inheritance Hierarchy 391
Designing Our API Using the Template 392
Moving Down to the Next Layer: What the View Passes to the Template 393
The Next “Requirement” from the Views Layer: New Lists Should Record
Owner 394
A Decision Point: Whether to Proceed to the Next Layer with a Failing
Test 395
Moving Down to the Model Layer 396
Final Step: Feeding Through the .name API from the Template 398

23. Test Isolation, and “Listening to Your Tests”. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401


Revisiting Our Decision Point: The Views Layer Depends on Unwritten
Models Code 401
A First Attempt at Using Mocks for Isolation 402
Using Mock side_effects to Check the Sequence of Events 404
Listen to Your Tests: Ugly Tests Signal a Need to Refactor 406
Rewriting Our Tests for the View to Be Fully Isolated 406
Keep the Old Integrated Test Suite Around as a Sanity Check 406
A New Test Suite with Full Isolation 407
Thinking in Terms of Collaborators 407
Moving Down to the Forms Layer 412
Keep Listening to Your Tests: Removing ORM Code from Our Application 413
Finally, Moving Down to the Models Layer 416
Back to Views 419
The Moment of Truth (and the Risks of Mocking) 420
Thinking of Interactions Between Layers as “Contracts” 421
Identifying Implicit Contracts 422
Fixing the Oversight 424
One More Test 425

xii | Table of Contents

WOW! eBook
www.wowebook.org
Tidy Up: What to Keep from Our Integrated Test Suite 426
Removing Redundant Code at the Forms Layer 426
Removing the Old Implementation of the View 427
Removing Redundant Code at the Forms Layer 429
Conclusions: When to Write Isolated Versus Integrated Tests 429
Let Complexity Be Your Guide 430
Should You Do Both? 431
Onwards! 431

24. Continuous Integration (CI). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433


Installing Jenkins 433
Configuring Jenkins 434
Initial Unlock 435
Suggested Plugins for Now 435
Configuring the Admin User 435
Adding Plugins 437
Telling Jenkins Where to Find Python 3 and Xvfb 437
Finishing Off with HTTPS 438
Setting Up Our Project 438
First Build! 439
Setting Up a Virtual Display So the FTs Can Run Headless 441
Taking Screenshots 443
If in Doubt, Try Bumping the Timeout! 447
Running Our QUnit JavaScript Tests in Jenkins with PhantomJS 448
Installing node 448
Adding the Build Steps to Jenkins 449
More Things to Do with a CI Server 451

25. The Token Social Bit, the Page Pattern, and an Exercise for the Reader. . . . . . . . . . . 453
An FT with Multiple Users, and addCleanup 453
The Page Pattern 455
Extend the FT to a Second User, and the “My Lists” Page 458
An Exercise for the Reader 459

26. Fast Tests, Slow Tests, and Hot Lava. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463


Thesis: Unit Tests Are Superfast and Good Besides That 464
Faster Tests Mean Faster Development 465
The Holy Flow State 465
Slow Tests Don’t Get Run as Often, Which Causes Bad Code 465
We’re Fine Now, but Integrated Tests Get Slower Over Time 465
Don’t Take It from Me 466
And Unit Tests Drive Good Design 466

Table of Contents | xiii

WOW! eBook
www.wowebook.org
The Problems with “Pure” Unit Tests 466
Isolated Tests Can Be Harder to Read and Write 466
Isolated Tests Don’t Automatically Test Integration 466
Unit Tests Seldom Catch Unexpected Bugs 466
Mocky Tests Can Become Closely Tied to Implementation 467
But All These Problems Can Be Overcome 467
Synthesis: What Do We Want from Our Tests, Anyway? 467
Correctness 467
Clean, Maintainable Code 467
Productive Workflow 468
Evaluate Your Tests Against the Benefits You Want from Them 468
Architectural Solutions 469
Ports and Adapters/Hexagonal/Clean Architecture 469
Functional Core, Imperative Shell 469
Conclusion 470
Further Reading 470

Obey the Testing Goat!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473

A. PythonAnywhere. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475

B. Django Class-Based Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479

C. Provisioning with Ansible. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491

D. Testing Database Migrations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497

E. Behaviour-Driven Development (BDD). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503

F. Building a REST API: JSON, Ajax, and Mocking with JavaScript. . . . . . . . . . . . . . . . . . . . 519

G. Django-Rest-Framework. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541

H. Cheat Sheet. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553

I. What to Do Next. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557

J. Source Code Examples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561

Bibliography. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565

Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567

xiv | Table of Contents

WOW! eBook
www.wowebook.org
Preface

This book is my attempt to share with the world the journey I’ve taken from “hack‐
ing” to “software engineering”. It’s mainly about testing, but there’s a lot more to it, as
you’ll soon see.
I want to thank you for reading it.
If you bought a copy, then I’m very grateful. If you’re reading the free online version,
then I’m still grateful that you’ve decided it’s worth spending some of your time on.
Who knows, perhaps once you get to the end, you’ll decide it’s good enough to buy a
real copy for yourself or for a friend.
If you have any comments, questions, or suggestions, I’d love to hear from you. You
can reach me directly via [email protected], or on Twitter @hjwp. You
can also check out the website and my blog, and there’s a mailing list.
I hope you’ll enjoy reading this book as much as I enjoyed writing it.

Why I Wrote a Book About Test-Driven Development


“Who are you, why are you writing this book, and why should I read it?” I hear you ask.
I’m still quite early on in my programming career. They say that in any discipline, you
go from apprentice, to journeyman, and eventually, sometimes, on to master. I’d say
that I’m—at best—a journeyman programmer. But I was lucky enough, early on in
my career, to fall in with a bunch of TDD fanatics, and it made such a big impact on
my programming that I’m burning to share it with everyone. You might say I have the
enthusiasm of a recent convert, and the learning experience is still a recent memory
for me, so I hope I can still empathise with beginners.
When I first learned Python (from Mark Pilgrim’s excellent Dive Into Python), I came
across the concept of TDD, and thought “Yes. I can definitely see the sense in that.”
Perhaps you had a similar reaction when you first heard about TDD? It sounds like a

xv

WOW! eBook
www.wowebook.org
really sensible approach, a really good habit to get into—like regularly flossing your
teeth.
Then came my first big project, and you can guess what happened—there was a cli‐
ent, there were deadlines, there was lots to do, and any good intentions about TDD
went straight out of the window.
And, actually, it was fine. I was fine.
At first.
At first I knew I didn’t really need TDD because it was a small website, and I could
easily test whether things worked by just manually checking it out. Click this link
here, choose that drop-down item there, and this should happen. Easy. This whole
writing tests thing sounded like it would have taken ages, and besides, I fancied
myself, from the full height of my three weeks of adult coding experience, as being a
pretty good programmer. I could handle it. Easy.
Then came the fearful goddess Complexity. She soon showed me the limits of my
experience.
The project grew. Parts of the system started to depend on other parts. I did my best
to follow good principles like DRY (Don’t Repeat Yourself), but that just led to some
pretty dangerous territory. Soon I was playing with multiple inheritance. Class hierar‐
chies eight levels deep. eval statements.
I became scared of making changes to my code. I was no longer sure what depended
on what, and what might happen if I changed this code over here, oh gosh, I think that
bit over there inherits from it—no, it doesn’t, it’s overriden. Oh, but it depends on
that class variable. Right, well, as long as I override the override it should be fine. I’ll
just check—but checking was getting much harder. There were lots of sections to the
site now, and clicking through them all manually was starting to get impractical. Bet‐
ter to leave well enough alone, forget refactoring, just make do.
Soon I had a hideous, ugly mess of code. New development became painful.
Not too long after this, I was lucky enough to get a job with a company called
Resolver Systems (now PythonAnywhere), where Extreme Programming (XP) was
the norm. They introduced me to rigorous TDD.
Although my previous experience had certainly opened my mind to the possible ben‐
efits of automated testing, I still dragged my feet at every stage. “I mean, testing in
general might be a good idea, but really? All these tests? Some of them seem like a
total waste of time… What? Functional tests as well as unit tests? Come on, that’s
overdoing it! And this TDD test/minimal-code-change/test cycle? This is just silly!
We don’t need all these baby steps! Come on, we can see what the right answer is, why
don’t we just skip to the end?”

xvi | Preface

WOW! eBook
www.wowebook.org
Believe me, I second-guessed every rule, I suggested every shortcut, I demanded justi‐
fications for every seemingly pointless aspect of TDD, and I came out seeing the wis‐
dom of it all. I’ve lost count of the number of times I’ve thought “Thanks, tests”, as a
functional test uncovers a regression we would never have predicted, or a unit test
saves me from making a really silly logic error. Psychologically, it’s made development
a much less stressful process. It produces code that’s a pleasure to work with.
So, let me tell you all about it!

Aims of This Book


My main aim is to impart a methodology—a way of doing web development, which I
think makes for better web apps and happier developers. There’s not much point in a
book that just covers material you could find by Googling, so this book isn’t a guide
to Python syntax, or a tutorial on web development per se. Instead, I hope to teach
you how to use TDD to get more reliably to our shared, holy goal: clean code that
works.
With that said: I will constantly refer to a real practical example, by building a web
app from scratch using tools like Django, Selenium, jQuery, and Mock. I’m not
assuming any prior knowledge of any of these, so you should come out of the other
end of this book with a decent introduction to those tools, as well as the discipline of
TDD.
In Extreme Programming we always pair-program, so I’ve imagined writing this book
as if I was pairing with my previous self, having to explain how the tools work and
answer questions about why we code in this particular way. So, if I ever take a bit of a
patronising tone, it’s because I’m not all that smart, and I have to be very patient with
myself. And if I ever sound defensive, it’s because I’m the kind of annoying person
that systematically disagrees with whatever anyone else says, so sometimes it takes a
lot of justifying to convince myself of anything.

Outline
I’ve split this book into three parts.
Part I (Chapters 1–7): The basics
Dives straight into building a simple web app using TDD. We start by writing a
functional test (with Selenium), and then we go through the basics of Django—
models, views, templates—with rigorous unit testing at every stage. I also intro‐
duce the Testing Goat.

Preface | xvii

WOW! eBook
www.wowebook.org
Part II (Chapters 8–17): Web development essentials
Covers some of the trickier but unavoidable aspects of web development, and
shows how testing can help us with them: static files, deployment to production,
form data validation, database migrations, and the dreaded JavaScript.
Part III (Chapters 18–26): More advanced testing topics
Mocking, integrating a third-party system, test fixtures, Outside-In TDD, and
Continuous Integration (CI).
On to a little housekeeping…

Conventions Used in This Book


The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
Used for program listings, as well as within paragraphs to refer to program ele‐
ments such as variable or function names, databases, data types, environment
variables, statements, and keywords.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Occasionally I will use the symbol:
[...]
to signify that some of the content has been skipped, to shorten long bits of output, or
to skip down to a relevant section.

This element signifies a tip or suggestion.

This element signifies a general note or aside.

xviii | Preface

WOW! eBook
www.wowebook.org
This element indicates a warning or caution.

Submitting Errata
Spotted a mistake or a typo? The sources for this book are available on GitHub, and
I’m always very happy to receive issues and pull requests: https://github.com/hjwp/
Book-TDD-Web-Dev-Python/.

Using Code Examples


Code examples are available at https://github.com/hjwp/book-example/; you’ll find
branches for each chapter there (e.g., https://github.com/hjwp/book-example/tree/chap
ter_unit_test_first_view). You’ll find a full list, and some suggestions on ways of work‐
ing with this repository, in Appendix J.
This book is here to help you get your job done. In general, if example code is offered
with this book, you may use it in your programs and documentation. You do not
need to contact us for permission unless you’re reproducing a significant portion of
the code. For example, writing a program that uses several chunks of code from this
book does not require permission. Selling or distributing a CD-ROM of examples
from O’Reilly books does require permission. Answering a question by citing this
book and quoting example code does not require permission. Incorporating a signifi‐
cant amount of example code from this book into your product’s documentation does
require permission.
We appreciate, but do not require, attribution. An attribution usually includes the
title, author, publisher, and ISBN. For example: “Test-Driven Development with
Python, 2nd edition, by Harry J.W. Percival (O’Reilly). Copyright 2017 Harry Percival,
978-1-491-95870-4.”
If you feel your use of code examples falls outside fair use or the permission given
above, feel free to contact us at [email protected].

O’Reilly Safari
Safari (formerly Safari Books Online) is a membership-based
training and reference platform for enterprise, government,
educators, and individuals.

Preface | xix

WOW! eBook
www.wowebook.org
Members have access to thousands of books, training videos, Learning Paths, interac‐
tive tutorials, and curated playlists from over 250 publishers, including O’Reilly
Media, Harvard Business Review, Prentice Hall Professional, Addison-Wesley Profes‐
sional, Microsoft Press, Sams, Que, Peachpit Press, Adobe, Focal Press, Cisco Press,
John Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe
Press, FT Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, and
Course Technology, among others.
For more information, please visit http://oreilly.com/safari.

Contacting O’Reilly
If you’d like to get in touch with my beloved publisher with any questions about this
book, contact details follow:

O’Reilly Media, Inc.


1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)

We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at http://bit.ly/tdd_py_2e.
To comment or ask technical questions about this book, send email to bookques‐
[email protected].
For more information about books, courses, conferences, and news, see O’Reilly’s
website at http://www.oreilly.com.
Facebook: http://facebook.com/oreilly
Twitter: http://twitter.com/oreillymedia
YouTube: http://www.youtube.com/oreillymedia

xx | Preface

WOW! eBook
www.wowebook.org
Prerequisites and Assumptions

Here’s an outline of what I’m assuming about you and what you already know, as well
as what software you’ll need ready and installed on your computer.

Python 3 and Programming


I’ve tried to write this book with beginners in mind, but if you’re new to program‐
ming, I’m assuming that you’ve already learned the basics of Python. So if you haven’t
already, do run through a Python beginner’s tutorial or get an introductory book like
Dive Into Python or Learn Python the Hard Way, or, just for fun, Invent Your Own
Computer Games with Python, all of which are excellent introductions.
If you’re an experienced programmer but new to Python, you should get along just
fine. Python is joyously simple to understand.
I’m using Python 3 for this book. When I wrote the first edition in 2013–14, Python 3
had been around for several years, and the world was just about on the tipping point
at which it was the preferred choice. You should be able to follow this book on Mac,
Windows, or Linux. Detailed installation instructions for each OS follow.

This book was tested against Python 3.6. If you’re on an earlier ver‐
sion, you will find minor differences (the f-string syntax, for exam‐
ple), so you’re best off upgrading if you can.

I wouldn’t recommend trying to use Python 2, as the differences are more substantial.
You’ll still be able to carry across all the lessons you learn in this book if your next
project happens to be in Python 2. But spending time figuring out whether the reason
your program output looks different from mine is because of Python 2, or because
you made an actual mistake, won’t be time spent productively.

xxi

WOW! eBook
www.wowebook.org
If you are thinking of using PythonAnywhere (the PaaS startup I work for), rather
than a locally installed Python, you should go and take a quick look at Appendix A
before you get started.
In any case, I expect you to have access to Python, to know how to launch it from a
command line, and to know how to edit a Python file and run it. Again, have a look
at the three books I recommended previously if you’re in any doubt.

If you already have Python 2 installed, and you’re worried that


installing Python 3 will break it in some way, don’t! Python 3 and 2
can coexist peacefully on the same system, particularly if you’re
using a virtualenv, which we will be.

How HTML Works


I’m also assuming you have a basic grasp of how the web works—what HTML is,
what a POST request is, and so on. If you’re not sure about those, you’ll need to find a
basic HTML tutorial; there are a few at http://www.webplatform.org/. If you can figure
out how to create an HTML page on your PC and look at it in your browser, and
understand what a form is and how it might work, then you’re probably OK.

Django
The book uses the Django framework, which is (probably) the most well-established
web framework in the Python world. I’ve written the book assuming that the reader
has no prior knowledge of Django, but if you’re new to Python and new to web devel‐
opment and new to testing, you may occasionally find that there’s just one too many
topics and sets of concepts to try and take on board. If that’s the case, I recommend
taking a break from the book, and taking a look at a Django tutorial. DjangoGirls is
the best, most beginner-friendly tutorial I know of. The official tutorial is also excel‐
lent for more experienced programmers.
Read on for instructions on installing Django.

JavaScript
There’s a little bit of JavaScript in the second half of the book. If you don’t know Java‐
Script, don’t worry about it until then, and if you find yourself a little confused, I’ll
recommend a couple of guides at that point.

xxii | Prerequisites and Assumptions

WOW! eBook
www.wowebook.org
A Note on IDEs
If you’ve come from the world of Java or .NET, you may be keen to use an IDE for
your Python coding. They have all sorts of useful tools, including VCS integration,
and there are some excellent ones out there for Python. I used one myself when I was
starting out, and I found it very useful for my first couple of projects.
Can I suggest (and it’s only a suggestion) that you don’t use an IDE, at least for the
duration of this tutorial? IDEs are much less necessary in the Python world, and I’ve
written this whole book with the assumption that you’re just using a basic text editor
and a command line. Sometimes, that’s all you have—when you’re working on a
server, for example—so it’s always worth learning how to use the basic tools first and
understanding how they work. It’ll be something you always have, even if you decide
to go back to your IDE and all its helpful tools, after you’ve finished this book.

Required Software Installations


Aside from Python, you’ll need:
The Firefox web browser
Selenium can actually drive any of the major browsers, but Firefox is the best to
use as an example because it’s reliably cross-platform and, as a bonus, is less sold
out to corporate interests.
The Git version control system
This is available for any platform, at http://git-scm.com/. On Windows, this comes
with the Bash command line, which is needed for the book.
A virtualenv with Python 3, Django 1.11, and Selenium 3 in it
Python’s virtualenv and pip tools now come bundled with Python 3.4+ (they
didn’t always used to, so this is a big hooray). Detailed instructions for preparing
your virtualenv follow.
Geckodriver
This is the driver that will let us remotely control Firefox via Selenium. I’ll point
to a download link in “Installing Firefox and Geckodriver” on page xxvi.

Prerequisites and Assumptions | xxiii

WOW! eBook
www.wowebook.org
Windows Notes
Windows users can sometimes feel a little neglected in the open source world, since
macOS and Linux are so prevalent, making it easy to forget there’s a world outside the
Unix paradigm. Backslashes as directory separators? Drive letters? What? Still, it is
absolutely possible to follow along with this book on Windows. Here are a few tips:

1. When you install Git for Windows, make sure you choose “Run Git and
included Unix tools from the Windows command prompt”. You’ll then get
access to a program called “Git Bash”. Use this as your main command prompt
and you’ll get all the useful GNU command-line tools like ls, touch, and grep,
plus forward-slash directory separators.
2. Also in the Git installer, choose “Use Windows’ default console”; otherwise,
Python won’t work properly in the Git-Bash window.
3. When you install Python 3, unless you already have Python 2 and want to keep it
as your default, tick the option that says “Add Python 3.6 to PATH” as in
Figure P-1, so that you can easily run Python from the command line.

Figure P-1. Add Python to the system path from the installer

xxiv | Prerequisites and Assumptions

WOW! eBook
www.wowebook.org
The test for all this is that you should be able to go to a Git-
Bash command prompt and just run python or pip from any
folder.

MacOS Notes
MacOS is a bit more sane than Windows, although getting pip installed was still fairly
challenging up until recently. Since the arrival of 3.4, things are now quite
straightforward:

• Python 3.6 should install without a fuss from its downloadable installer. It will
automatically install pip, too.
• Git’s installer should also “just work”.

Similarly to Windows, the test for all this is that you should be able to open a terminal
and just run git, python3, or pip from anywhere. If you run into any trouble, the
search terms “system path” and “command not found” should provide good trouble‐
shooting resources.

You might also want to check out Homebrew. It used to be the


only reliable way of installing lots of Unixy tools (including
Python 3) on a Mac.1 Although the normal Python installer is
now fine, you may find Homebrew useful in future. It does
require you to download all 1.1 GB of Xcode, but that also
gives you a C compiler, which is a useful side effect.

Git’s Default Editor, and Other Basic Git Config


I’ll provide step-by-step instructions for Git, but it may be a good idea to get a bit of
configuration done now. For example, when you do your first commit, by default vi
will pop up, at which point you may have no idea what to do with it. Well, much as vi
has two modes, you then have two choices. One is to learn some minimal vi com‐
mands (press the i key to go into insert mode, type your text, press <Esc> to go back to

1 I wouldn’t recommend installing Firefox via Homebrew though: brew puts the Firefox binary in a strange
location, and it confuses Selenium. You can work around it, but it’s simpler to just install Firefox in the nor‐
mal way.

Prerequisites and Assumptions | xxv

WOW! eBook
www.wowebook.org
normal mode, then write the file and quit with :wq<Enter>). You’ll then have joined
the great fraternity of people who know this ancient, revered text editor.
Or you can point-blank refuse to be involved in such a ridiculous throwback to the
1970s, and configure Git to use an editor of your choice. Quit vi using <Esc> followed
by :q!, then change your Git default editor. See the Git documentation on basic Git
configuration.

Installing Firefox and Geckodriver


Firefox is available as a download for Windows and macOS from https://
www.mozilla.org/firefox/. On Linux, you probably already have it installed, but other‐
wise your package manager will have it.
Geckodriver is available from https://github.com/mozilla/geckodriver/releases. You
need to download and extract it and put it somewhere on your system path.

• For macOS or Linux, one convenient place to put it is ~/.local/bin


• For Windows, put it in your Python Scripts folder

To test that you’ve got this working, open up a Bash console and you should be able
to run:
geckodriver --version
geckodriver 0.17.0

The source code of this program is available at


https://github.com/mozilla/geckodriver.

This program is subject to the terms of the Mozilla Public License 2.0.
You can obtain a copy of the license at https://mozilla.org/MPL/2.0/.

If it doesn’t work, it may be that ~/.local/bin isn’t on your PATH (this would apply to
some Mac and Linux systems). It’s a good idea to have this folder on your path
because it’s where Python will install things when you use pip install --user.
Here’s how to add it in your .bashrc:2
echo 'PATH=~/.local/bin:$PATH' >> ~/.bashrc

Close your terminal and re-open it and see if the geckodriver --version works
now.

2 .bashrc is an initialization file for Bash that lives in your home folder. It gets run every time you start Bash.

xxvi | Prerequisites and Assumptions

WOW! eBook
www.wowebook.org
Setting Up Your Virtualenv
A Python virtualenv (short for virtual environment) is how you set up your environ‐
ment for different Python projects. It allows you to use different packages (e.g., differ‐
ent versions of Django, and even different versions of Python) in each project. And
because you’re not installing things system-wide, it means you don’t need root
permissions.
Virtualenv has been included in Python since version 3.4, but I always recommend a
helper tool called “virtualenvwrapper”. Let’s install that first (it doesn’t matter which
version of Python you install it for):
# on Windows
pip install virtualenvwrapper
# on macOS / Linux
pip install --user virtualenvwrapper
# then make Bash load virtualenvwrapper automatically
echo "source virtualenvwrapper.sh" >> ~/.bashrc
source ~/.bashrc

On Windows, virtualenvwrapper will only work inside the “Git-


Bash” shell, not from the normal command line.

virtualenvwrapper keeps all your virtualenvs in one place, and provides convenient
tools for activating and deactivating them.
Let’s create a virtualenv called “superlists”3 that has Python 3 installed:
# on macOS/Linux:
mkvirtualenv --python=python3.6 superlists
# on Windows
mkvirtualenv --python=`py -3.6 -c"import sys; print(sys.executable)"` superlists
# (a little hack to make sure we get a python 3.6 virtualenv)

Activating and Deactivating the Virtualenv


Whenever you work on the book, you’ll want to make sure your virtualenv is “active”.
You can usually tell because you’ll see (superlists) in parentheses, in your prompt.
Something like this:
$
(superlists) $

3 Why superlists, I hear you ask? No spoilers! You’ll find out in the next chapter.

Prerequisites and Assumptions | xxvii

WOW! eBook
www.wowebook.org
Exploring the Variety of Random
Documents with Different Content
keep a family of four properly alive.”
“You can bet your bottom dollar it isn’t. I’ve been with them enough
to note the little pinchings and scrimpings and they make my heart
bleed. It is up to us, one or the other of us, to climb into the breach,
and I have found the way to do it. There is a spare bed-room in the
cottage, and last evening I asked Mrs. Dabney if she would be
willing to take a lodger. She was so willing that she cried.”
“Well?” said Philip.
“As I say, it’s up to us—or one of us; the room isn’t big enough for
two.”
“Go over there and live with them, you mean?”
“That’s it. And since they were your friends before they were mine,
you shall have the first chance at it. But if you don’t go, I shall. They
need the money. Think it over, and we’ll thresh it out after I come
back.”
For some time after Bromley had gone, Philip sat in his reading chair
thrilling to his finger-tips. To live under the same roof with Jean; to
be with her daily in the close intimacies of the home life; to be able
to help her legitimately in the carrying of her heavy burden until the
time should come when, his own filial duty discharged and the Trask
name cleared, he might persuade her to shift the burden to his
shoulders—to his and not to Harry Bromley’s.... There was only one
fly in this precious pot of ointment: that saying of Jean’s scarcely an
hour old: “I suppose I am like other women. When the time comes—
if it ever does come—that I think enough of a man to marry him, I
shan’t ask what he has been; only what he is and means to be.” Was
she trying to tell him that Bromley was the man?
It was in that hour that the virtuous ego rose to its most self-
satisfied height. Jean, wise in the hard school of adversity but
innocent as a child in matters touching her soul’s welfare, should be
made to see that she must not risk her future happiness by marrying
any man who, however lovable, had once shown the weak thread in
the fabric of his character and might show it again. It should be his
task to make her see it; to convince her that her duty to herself and
to her unborn children lay in quite a different direction.
In the levitating exhilaration of this thought the room suddenly
became too close and confining to contain him, and he put on his
coat and hat and descended to the street. Conscious only of an urge
to keep moving, he began to walk aimlessly, through Curtis to
Sixteenth Street, past the new opera house now nearing completion,
and so on down toward Larimer.
It was in the final block that he saw something that jerked him down
out of the clouds and set his feet upon the pavement of the baser
realities. In the center of the block was one of the evidences of
Denver’s “wide-openness”: a luxurious gambling palace running, like
many others in the city of the moment, without let or hindrance from
the police. Through the green baize swinging doors, as he was
passing, Philip saw an entering figure and recognized it.
“Jim Garth!” he muttered, and hung upon his heel. He knew that
Bromley had been “staking” the big miner from time to time, and
had himself refused point blank to join in the contributions, arguing
that it was not only good money thrown away, but that it was merely
giving a man of ungoverned appetites the means of further
degrading himself. But now, in an upsurge of righteous responsibility
—the legitimate child of the thoughts he had been entertaining—he
was moved to lay a restraining hand upon this weak-willed giant who
had toiled with him and Bromley through the bitter winter in the
Saguache. Before he realized exactly what he meant to do, or how
he should go about it, he had pushed the swinging doors apart and
was ascending the softly carpeted stair.
At the top of the stair he found a doorkeeper guard, but with a
single appraising glance the man let him pass into the room beyond.
For a moment he stood just inside the door, blinking and bewildered.
The transition from the cool outdoor air and semi-darkness of the
street to the brilliant light and smoke-drenched atmosphere of the
crowded upper room dazed him. It was the first time he had ever set
foot within a gambling “hell,” and it was some little time before he
could force himself to begin a slow circuit of the room in search of
Garth.
To the soul inspired by predetermined righteousness the scene was a
blasting commentary on the depravity of human nature. The
haggard, eager, lusting faces of some of the players contrasting with
the blank immobility of others—the seasoned gamblers; the
monotonous click of the chips as some nervous amateur ran them
through his fingers; the skirling spin of the roulette balls followed by
the rat-tat-tat as they came to rest in the red or black.... Philip saw
and heard and hastened, with a feeling that if he should linger too
long the fell madness of the place might somehow obtain a
lodgment in his own brain. He must find Garth quickly and drag him
out.
It was at the upper end of the room that he came to a green-
covered table with inlaid cards in its center and a double row of
players ringing it, the inner row sitting and the outer standing. Upon
a high stool at one end sat the “lookout,” a man with the face of a
graven image and watchful eyes that marked each bet as it was
placed upon the table; and at one side sat the dealer, turning up
cards with practiced dexterity out of the nickel-plated box on the
table before him.
Philip’s gaze swept the ring of faces until he came to that of the
shirt-sleeved dealer, flipping the cards two by two with automatic
precision out of the box under his hands. One glance at the clean-
cut, deeply lined face with its cold eyes, thin nostrils and lean jaw
was all that was needed, and Philip’s heart skipped a beat and stood
still. His fruitless search of the past few weeks for his father had
ended—here!
Gropingly, and as if his sight had suddenly failed him, he edged his
way around the table and touched the shirt-sleeved man on the
shoulder. The cold gray eyes were lifted to his for a flitting instant;
then the dealer made a sign to his substitute and got up from his
place, saying quietly to Philip: “I’ve been expecting you. We’ll go up-
stairs.”
Wholly speechless, Philip followed his father into the hall, up a
stairway and into a room on the third floor where a gas jet, turned
low, was burning. John Trask reached up and turned the gas on full.
“Might as well sit down,” he said to his son; and Philip sank into a
chair and fought for speech. But the words would not come. The
crushing silence was broken at length by the father.
“You’ve been looking for me?”
Philip nodded and moistened his dry lips to say, “Everywhere.”
“I thought most likely you might—after I saw your name in the
papers as one of the ‘lucky-strikers.’” Then: “You knew me—without
the beard?”
“Of course,” said Philip dully. “You look just the same, only older.”
“I am older; a good deal older than the six years will account for. Tell
me about your mother and sisters: you hear from them, don’t you?”
“They are well—and well provided for, now.”
“I suppose they have given me up for dead, haven’t they?”
“I don’t know; I only know that I hadn’t.”
“Maybe it would have been better if you had.”
“No!” Philip broke in desperately. “There is something for you to do—
a thing I can help you do, now that I have money.”
“What is it?”
“To go back to New Hampshire with me and fight those liars, who
said you stole from the bank, to a finish in the courts; to make the
Trask name once more what it has always been—an honest one. I’ll
back you, to the last dollar there is in my half of the mine.”
The thin lips of the older man parted in the ghost of a smile.
“Spoken like a good son—or at least a dutiful one,” he said, in a tone
that seemed slightly acid. “But why be so anxious about the name?”
“Why?—why?” Philip demanded. “Why shouldn’t I be anxious about
it? Isn’t it the name I bear?”
“A name is nothing unless you make it something—but we won’t
argue about that. You say you want me to go back to New
Hampshire and set things right. It hasn’t occurred to you that there
might be a certain difficulty in the way?”
“You mean the fact that you didn’t stay and fight it out at the time?”
The ghost of a smile came again.
“No; I didn’t mean that. I mean the fact that not all of your money
could help me to prove what isn’t so. I took the money from the
bank; stole it, you’ll say, though I chose to call it squaring accounts
with Hiram Witherspoon, who had kept me on starvation wages for
years. I took it and got away with it.”
Once again Philip’s heart skipped a beat and stopped, and for a
moment the room whirled in dizzying circles for him.
“You—you stole it?” he faltered, in a voice that he scarcely
recognized as his own. Then, helplessly: “I—I don’t understand.”
“You wouldn’t,” was the curt reply, “you are too much of a Sanborn.
They never kick over the traces.” A pause, and then: “You’d never
understand in a month of Sundays, Phil. Your grandfather was a
hard man and a hypocrite. He never took his hand off my collar until
after I was a man grown—bull-necked me into everything I ever did,
even to my marriage with your mother, forgetting that I had the
same blood in me that he had in him. He lived a double life until he
died, and thought nobody knew; but I knew, and I did the same
until the time came when I could help myself and bolt—with the
other woman.”
“Oh, my God!” Philip groaned, and covered his face with his hands to
shut out the sight of the man who sat opposite, calmly indifferent,
as it seemed, to the havoc he had wrought.
When Philip looked up it was to say harshly: “Where is the other
woman now?”
“She is here—in Denver. She does a turn now and then at the
Corinthian when the cards run queer for me.”
Philip staggered to his feet in a desolate rage.
“Then I’m the son of a thief, a gambler and the paramour of a kept
woman!” he blazed out madly. “That’s the name I bear, is it?—the
reward I get for believing in you, like the damned fool that I was,
when everybody else was against you?” He shook his fist in his
father’s face. “Do you know what you’ve done to me? You’ve killed
my soul—that’s what you’ve done!—blasted my faith in all
humankind! Let me get out of here, before I—Oh, God!...”
He choked and clapped his hands to his face, stumbling toward the
door. As he fumbled for the knob and twisted it, the chill voice
behind him said: “You had no call to chase me, and you needn’t
worry about the name. I haven’t called myself John Trask since I left
New Hampshire. And one thing more: I’ve put a bullet through a
man before this for saying less than you said a minute ago. That’s
all, I guess.”
Philip groped his way through the upper passage and down the two
flights of stairs to the sidewalk. The reaction from the fit of mad
rage set in as he stepped into the open air and he went suddenly
weak and nauseated. The Tabor Building was just opposite, and in
the alley beside it he saw the light of the saloon at the back. Two
minutes later he had staggered across the street, up the alley and
into the lighted bar-room, which proved to be momentarily empty of
other patrons. “Whiskey!” he gasped, leaning against the bar. “I’m
sick!”
The bartender set out the bottle and a glass of water, and spun the
empty whiskey glass along the polished mahogany. With a hand that
was shaking as if with palsy, Philip tilted the bottle, poured himself a
drink that ignored the miniature pig etched in the side of the glass
with the motto, “Don’t drown the hog,” and gulped it down. The
neat liquor was like a draft of liquid fire to his unaccustomed palate
and throat, and he choked and strangled until the bartender reached
over and put the glass of water into his hand with a grinning
comment: “Guess you hain’t got the knack yet o’ takin’ it straight,
son. Wash ’er down with a chaser o’ water.”
With his throat still afire, Philip took to the streets. Since the huge
drink he had just swallowed was the first he had ever taken, its
intoxicating effect was almost instantaneous. Before he had walked
half a dozen blocks his brain was spinning and he fancied he was
treading upon thin air. From that time on, consciousness faded little
by little; all he knew was that he was walking, walking endlessly,
sometimes through streets that seemed dimly familiar, at other times
with all the surroundings singularly strange.
Finally he found himself climbing what he took to be the steps of the
Alamo Building to his rooms, drenched and permeated now with an
overpowering desire to sleep. In some odd way the steps did not
seem quite right; there were not enough of them. And there was a
lighted door at the top which was opened for him before he could
reach for the knob. It was at this conjuncture that reasoning
consciousness forsook him completely. He had a vague impression
that somebody—Bromley it would be, of course,—was leading him
somewhere; that his feet, from being so lately shod with wings, had
become unaccountably leaden; that there were more steps to be
climbed; and after that, the oblivion of a sleep profound and trance-
like.
When he awoke he found himself lying, fully clothed, upon a bed in
a strange room. The window shades were drawn, but the morning
sun was shining upon them. On the edge of the bed, with her single
garment slipping over one shoulder, sat a girl with carmined lips and
pencilled eyebrows; she was laughing at him and saying: “Had a
good sleep, honey?” adding: “You certainly had a lovely jag on last
night when you turned up here. Did somebody dope you?”
Philip leaped up and slewed himself around to sit beside the strange
girl. The quick movement set a trip-hammer pounding in his head,
and he had to wince and press his temples and wait a minute before
he could master the throbbing pain and say, “Where am I?”
“As if you didn’t know!” she gibed. “You sure had a skinful, but I
guess you still knew enough to come where you’d be took care of.
Here’s your pocketbook. Wonder somebody didn’t nip it off you
before you got here.”
Slowly he began to realize where he was.
“Are you trying to tell me that I’ve been here all night, with you?”
“Oh, no; not with me; not any; just with yourself. A cannon wouldn’t
’ve waked you after we got you up-stairs.”
“What made you take me in?”
The girl laughed again and pointed at the pocketbook in his hands.
“That, and your good clothes. The madam said she knew you wasn’t
no dead-beat.”
Soberly he took a bank-note from the well-stuffed pocketbook and
gave it to her.
“Is that enough?” he asked. “I’m new to this sort of thing.”
The girl flung her arms around his neck and kissed him.
“You’re a dandy—a prince!” she said; and as he staggered to his feet
and reached for his hat: “Have you got to go, right away? If you’ll
wait, I’ll dig you up a cup of coffee for a bracer.”
“No; I’ll go.”
“All right; I’ll show you the way out. There ain’t nobody else up in
the house yet. It’s early.”
She ran down the stair ahead of him and snapped the night latch on
the front door to let him out. As he passed her she patted him softly
on the shoulder. “Good-by, honey, dear. You’ll come back again,
won’t you? And next time, for Pete’s sake, don’t get so parboiled
that you won’t know me.”
When he reached the sidewalk he turned to look back at the place.
He knew the house. It was one that Middleton had pointed out to
him a year in the past as one of the few places of the sort where, as
the fat-faced tonnage clerk had phrased it, “a man needn’t carry a
burglar-proof safe with him to be sure of finding his wallet when he
wakes up in the morning.”
Philip looked at his watch. It had run down and he swore at it under
his breath. The aftermath of the single gluttonous drink was still with
him in the shape of a parched throat, a dry tongue, a fiercely aching
head and a set of jangled nerves. At first, he thought he would go to
his rooms and take a cold bath; but after he had gone a block or two
in that direction he changed his mind and once more sought the
saloon in the rear of the Tabor Building. The night bartender was still
on duty and he grinned when Philip came in.
“Want a little of the hair o’ the dog that bit you, I reckon?” he said,
setting out the bottle and glasses.
Philip poured a drink, a small one, this time, and since the mere
smell of the liquor gagged him, he held his nose as he drank. The
stimulant steadied the twittering nerves; and it did more—it cleared
his brain and brought the desolating revelation of the night back
with a vividness that hurt like the stabbing of needles. He set his
watch by the bar-room clock. As the girl in the other street had said,
it was quite early. Bromley would not be up yet. Suddenly it came to
him that he could not face Bromley; not yet, at any rate. He must
eat breakfast first; and he went around to Charpiot’s for the meal.
The breakfast, a light one, for his stomach was still in revolt, was
hastily despatched; and as he was leaving the table the play-boy
came in.
“Hello, there!” he exclaimed. “You are still in town? I looked into
your room and saw your bed hadn’t been slept in, so I concluded
you’d taken a night train to somewhere.”
“No,” Philip replied soberly; “I haven’t been out of town.”
“Well, don’t rush off. Sit down and be neighborly while I get a bite of
breakfast.”
“No,” Philip repeated, “I’ve got to go.” Then he turned back and
forced himself to look his partner in the eyes. “That matter we were
talking about last night before you went to the theater: I’m not
going to take that room at the Dabneys’. You are the one to go
there.”
The play-boy looked his surprise.
“Why—what’s the matter with you, Phil? When I spoke of it last
night, I thought you looked tickled purple.”
“Last night was last night, and this morning is another day. Say that
I don’t care to give up the stuffy luxuries of the apartment in the
Alamo, if you like. Anyway, I’m not going to move; that is all there is
to it.”
And with this curt refusal he turned his back upon his partner and
left the dining-room.
XVII
Passing out through the hotel office with one thought effacing all
others, namely, that companionship of any sort was not to be
endured, Philip, a prey to the instinctive urge that drives the
wounded animal to seek a hiding place, pulled his hat over his eyes,
signalled to a passing cab and got in, telling the driver to take him to
the Alamo Building.
Reaching his rooms, he scribbled a note for Bromley, merely saying
that he was going out of town, filled a travelling-bag, jamming
things into it with little regard for long-established habits of care and
orderliness, and was presently on his way to the Union Depot,
urging the cab driver to haste and still more haste. By a margin of
seconds he caught the South Park train for Leadville; and as the
short string of top-heavy, narrow-gauge cars went swaying and
lurching out over the switches in the West Denver yard, he was
choosing an isolated seat in the chair-car where he could settle
himself to look the catastrophic revelation of the night fairly in the
face.
With the scene of the revelation actually withdrawing into the
distance, a vast incredulity seized him. Could it be possible that he
had grown up in daily association with his father without so much as
suspecting the existence of the iron-hard, desperate underman
biding its time beneath an exterior so like that of other men in his
walk of life as to be wholly unremarkable? It seemed fantastically
unbelievable. Yet, in looking back upon the conventional New
England home life he saw how it might be so.
The atmosphere of the home, as he had always known it, had been
one of silent restraint, and there had been nothing like man-to-man
comradeship between his father and himself. Not that this was at all
singular. He had known many other households in the homeland in
which the same spirit of reticence and aloofness, the same
repression of all the emotions, were the natural order of things. The
attitude was ingrained in the bone and blood; a heritage which, as
he now realized, was his and his forebears’; the bequeathing of the
stern stock which had fled from tyranny in England only to set up a
repressive tyranny of its own in the new land beyond the sea.
But such reflections as these did not serve to lessen the
completeness, the crushing completeness, of the blow that had
fallen. Where was now that righteous pride of race he had paraded
before Jean Dabney, the boast of honest and upright ancestors he
had so confidently made?—he, the son of a thief, a gambler, a
hardened breaker of the laws of God and man. Of what use to him
now was the growing hoard of gold in the Denver bank, since it
could never buy back that which was irretrievably lost? How could he
go on living from day to day with the knowledge that the accident of
any day might give some sensation-mongering newspaper reporter
the chance to write up Lucky-strike Trask of the “Little Jean” as the
son of a well-known local faro-dealer and sporting man? In his
mind’s eye he could visualize the mocking headlines, and a wave of
impotent rage, the agony of a tortured ego, swept over him.
He had no desire to eat when the train halted at the midday dinner
station and did not leave his place in the chair-car. Later, through the
long afternoon, he looked out, with eyes that saw without
perceiving, upon the passing panorama of canyon cliffs and forested
mountain slopes, of undulating distances in the South Park and the
uplifted peaks of the Mosquito Range, deep in the misery of his
wounding; aghast at the prospect of the future. It was with an
added degree of wretchedness that he realized that his love for Jean
Dabney, restrained and calmly calculated hitherto, seemed to have
been set free in the chaotic crash of things, blazing up in passionate
intensity now that its object was, as he told himself bitterly,
snatched out of reach. That he could never go to her with the story
of his humiliating discovery was the first sickening conclusion that
had burned itself into his consciousness; and now this was followed
by the appalling after-conclusion that he could not go to her at all;
that the discovery in the gambling hell had cut him off at once and
irrevocably from all association with her.
It was only natural that the thought of his own lapse, the fact that
he had taken his first drink and in the drunkenness of it had spent
the night in a brothel, seemed of small account in the general wreck.
With the family honor already dragged so deeply in the mire of
disgrace and criminality, what he might or might not do made little
difference one way or the other. Not that he cherished as yet any
desperate or boyish determination to take a fool’s revenge by
plunging into dissipation. There was only a dull indifference. Pride
was dead and the barriers of self-control had been broken down, but
life still had to be lived, in some fashion.
Upon arriving in Leadville he had himself driven to the hotel where
he and Bromley had put up after they had come out of the
mountains with Drew in the spring. Still having no desire to eat, he
tried to smoke; and when the pipe, on an empty stomach,
nauseated him, he went to the bar and called for a drink. As in the
morning, the swallow or two of whiskey wrought a miracle and he
sought the dining-room and ate a hearty meal. Afterward, with a
mild cigar that had none of the dizzying effects of the empty-
stomach pipe, he sat in the lobby, and it was there that Drew ran
across him.
“Back with us again, are you?” was the genial promoter’s greeting as
he drew up a chair and planted himself in it for his own after-dinner
smoke. “When did you reach?”
“Just an hour or so ago,” Philip answered, surprised to find himself
able to tolerate and even to welcome the companionship of the older
man. “I came up on the South Park day train.”
“And how is Henry Wigglesworth? Still making a quiet joke of the
world at large?”
“Harry is all right. Good luck hasn’t spoiled him, as I was afraid it
might.”
“Inclined to be a little wild, was he?” Drew remarked.
“When I first met him, yes. And I was foolish enough to think that I
had to brother him. Queer what notions a man gets into his head,
sometimes.”
Though he did not look aside, he knew that Drew was regarding him
curiously.
“You come of brothering stock, don’t you, Trask?”
“At one time I was ass enough to think so. That was another of the
queer notions. How is the ‘Little Jean’ coming along?”
“Splendidly. The vein values are increasing as we drive in on the
lode. We are making another clean-up from the plates this week,
and you’ll get a dividend that will warm the cockles of your heart.”
“Money,” said Philip half contemptuously. “When you don’t have it,
it’s the most desirable thing in the world. And when you get it——”
he broke off, leaving the sentence unfinished.
The promoter smiled. “Money is only a means to an end, of course.
If it is not too personal a question, what are you doing with yours?”
“Nothing, as yet. Bromley is investing his share here and there,
setting me a good example. But I haven’t followed it.”
From that the talk went back to the gulch on the western slope, and
Drew told how the shut-in valley had been overrun by prospectors as
soon as the snow was off. A few small leads had been discovered
higher up the gulch, but nothing at all comparable with the “Little
Jean.” Reference to the hard winter the discoverers of the “Little
Jean” had put in led Drew to ask about Garth; and the mention of
the big miner’s name stabbingly reminded Philip of the chance
incident in which Garth had figured, and which had led up to the
blotting out of all recollection of him.
“Garth is in Denver; or he was yesterday,” he replied.
“Pity about Jim,” said the promoter. “At bottom he’s a man, right; but
he can’t let liquor and the paste-boards alone. He has been
moderately well-fixed at least three times, to my certain knowledge,
and each time he has blown it all; gambled it and given it away—or
so much of it as he didn’t pass across the bar.”
Philip was conscious of a curious little shock when he realized that
this cataloguing of Garth’s weaknesses now stirred no resentful or
condemnatory emotion in him.
“Perhaps that is the way in which he gets the most out of life,” he
offered colorlessly. “There is no accounting for the difference in
tastes.”
“No; but Big Jim is really worth saving, if somebody would take the
trouble,” Drew put in, adding: “I don’t suppose anybody has ever
cared enough for him to try to brace him up—at least, nobody since
his wife died.”
“He was married?” Philip queried. “I worked beside him all winter
and never knew that.”
“It was one of those cases you read about—and seldom see in real
life,” Drew went on reminiscently. “It happened in one of the
intervals when Jim was on top, financially. A gambler, whose name I
have forgotten, brought a girl here from the East—a ‘chippy,’ I
suppose you’d call her—abused her shamefully, made her support
him for a time and then abandoned her. Jim heard about it, and
after marrying the girl off-hand, hunted up the gambler and shot
him within an inch of his life. The girl turned out to be a jewel as
Jim’s wife; stuck to him through thick and thin, and actually got him
to stop drinking and gambling. Then the altitude, and the hard life
she had lived before she met Jim, grabbed her and she died.
Naturally, poor old Jim went all to pieces again.”
“Naturally,” Philip agreed. His eyes were narrowed and he was
conscious of a curious deadening of the heart. The story of Garth’s
tragedy did not move him as it would have moved him no longer ago
than yesterday. Instead, he was asking himself why Garth shouldn’t
take to drink and dissipation to drown his grief? For that matter, why
shouldn’t any man, if he happened to lean that way?
Drew looked at his watch and rose.
“I have an appointment that I was about to forget,” he said.
“Intending to stop over with us for a while?”
“Perhaps. I haven’t made any plans.”
“All right; we’ll get together again. While you are here, my office is
at your disposal, of course. Come around and make it your loafing
place.”
After Drew had left him, Philip lighted another of the mild cigars and
took to the streets, walking until he was sodden with weariness.
Again and again the meager details of Garth’s tragedy passed
themselves in review. So the big miner had once made his little
gesture of righteousness by marrying a woman of the class for which
the world has no place of repentance, had he? That was fine! How
crassly he had misjudged Garth. Bromley’s insight had been better.
Was the play-boy’s assumption that there was no hard-and-fast line
to be drawn between the sheep and the goats—that there was good
in the worst and bad in the best—the right one, after all?
Philip’s thoughts went back to the scene of the early morning when
he had awakened to find a girl with pencilled eyebrows and painted
lips sitting on the edge of his bed in the strange room. “Scum of the
earth,” he had been calling her and her kind; and yet she, and her
still more degraded house mistress, had taken him in and cared for
him, and had not robbed him and turned him helpless into the
street, as they might have done. He had a vivid picture of the girl
sitting there and laughing at him as he opened his eyes. She was
pretty, in a way, and her talk and manner had given him the
impression of recklessness and misguiding rather than hardness.
Was she one of these who are more sinned against than sinning? He
wondered.
Tired out finally, he returned to the hotel and went to bed. In the life
which was already withdrawing into a far-away past he had always
been able to fall asleep as soon as his head touched the pillow; but
now, though it was past midnight and he was weary to utter
exhaustion, sleep would not come. Over and over the harrowing
details of the discovery of his father and the scene in the upper
room over the gambling den rehearsed themselves as he tossed and
tumbled and tried to banish them; and at last, in sheer desperation,
he got up and dressed and went down to the lobby floor. The bar-
room was closed, and he appealed to the night clerk, money in
hand.
“I’m sick and can’t sleep,” he said. “Couldn’t you break in back there
and get me a drink? I don’t want to take to the streets at this time
of night.”
The clerk smiled knowingly. “Got a hang-over, have you? I guess I
can fix you.” He disappeared, to return presently with a pint bottle of
whiskey. “Think that will do the business for you?” he asked.
“Yes; thanks. Don’t bother about the change.”
Once more in his room, he slipped out of his clothes, took a stiff
drink, and stretched himself upon the bed. In a little time the curious
and altogether pleasant feeling of levitation came and he floated off
through a spacious region of dreams which grew vaguer and vaguer
until they vanished in an abyss of forgetfulness.
XVIII
Bromley had been occupying the spare bed-room in the Dabney
cottage for nearly a fortnight on the Saturday when, calling at the
Windsor Hotel to tell the Follansbees about a bargain in furnished
houses he had happened to hear of, he saw Stephen Drew
registering in at the room clerk’s desk and crossed the lobby to
shake hands with him.
“This is a piece of luck,” said the lessee of the “Little Jean,” after the
greetings were passed. “I didn’t know your address and was
expecting to have to dig you up through the bank or the post-office.
I came down on business, but also I was anxious to get hold of you.
If you have a few minutes to spare——?”
“All the time there is,” returned the play-boy cheerfully, leading the
way to a couple of the lobby chairs. Then, with a laugh: “I hope you
are not going to tell me the ‘Little Jean’ is petering out.”
“Nothing like that. The mine is all right. The values are increasing, as
your next dividend will show. I wanted to talk to you about Trask. Do
you know where he is?”
“I haven’t the remotest idea. He dropped out between two minutes
one morning early last week, leaving a note which merely said that
he was vanishing. It’s all right, though. He has been making a good
many swings around the circle in the past month or so, on a sort of
still hunt for his—for a man he is trying to find.”
“Did you see him before he left Denver this last time?”
“Why, yes; I was with him the evening before he left; and I saw him,
for just a minute or two, the next morning.”
“Anything wrong with him then?”
Bromley took time to think back. Previous to that brittle meeting in
the breakfast-room at Charpiot’s, Philip had been out, somewhere,
all night. Now that he recalled it, he remembered that the meeting
had been only momentary; that Philip had looked rather the worse
for wear; that his refusal to take the spare room in the Dabney
cottage had been almost brutal in its abruptness.
“I can’t say there was anything definitely wrong,” he replied. “I
remember he looked a bit gloomy and wrought up, but that is
nothing new for him. He has pretty bad attacks of the New England
conscience at times—if you know what that means.”
Drew nodded. “I understand. But that isn’t to the point just now.
Your partner is in Leadville, and he is badly in need of a friend;
somebody near enough and intimate enough to take him by the
neck.”
Bromley laughed easily.
“There must be some mistake about that. Philip, himself, is the one
who rushes around taking people by the neck.”
“You are off wrong, this time,” the promoter cut in shortly. “I don’t
believe he has been entirely sober at any one time during the past
two weeks, and he seems to be permeated with an idea that he can
use up all the red paint there is and break all the gambling banks in
the camp if he only sticks at it long enough.”
“Good heavens!” Bromley gasped; “not Philip!”
“Yes, Philip. Of course, I understand that it’s none of my business,
but I hate to see such a fine, upstanding fellow as he is go to the
devil in a hand-basket. Has he had trouble of any sort?”
Bromley took a moment to consider whether or not he had a right to
breach Philip’s confidence in the matter of the search for his father,
and decided quickly that the present crisis warranted it. Very briefly
he told Drew the little he knew about the Trask family tragedy, and
of the futile search Philip had been making.
“Ah,” said the shrewd-witted developer of mines, “that may be the
clue. You say Philip believed in his father’s innocence?”
“Absolutely and utterly. But from what he has told me, I gathered
that he was pretty much alone in that belief; that, as a matter of
fact, not even the other members of the family shared it.”
“I see. Then that may be the key to the present situation. Trask is
pretty sensitive on the family honor question, and all that, isn’t he?”
“Exceedingly so. It, and his conscience, are his little tin gods.”
“There you are, then. You say his search for his father has been
futile. You don’t know positively that it was, do you?”
“It was, up to the night before he went to Leadville.”
“Well, many a man has had his world turned upside down for him
between dark and daylight in a single night. Whatever the cause
may have been, the effects are as I have indicated. Philip is setting a
pace that not even a half-share in a gold mine can stand indefinitely.
If you think you can do anything with him, you’d better go after him.
As I say, he is needing a friend mighty badly.”
“Sure I’ll go,” agreed the play-boy promptly. “I owe Philip a lot more
than I’ll ever be able to pay. And you mustn’t judge him by this one
fall-down, Mr. Drew. There are some people who suffer most from
an excess of their virtues—if you know what I mean—and Philip is
one of those. He has stood up stiff and straight all his life, and when
a fellow who lives that way gets bowled over——”
“I know,” assented the man of large experience. “The greatest
danger in a case of that kind lies in that ‘excess of the virtues’ you
speak of. When the barriers are once thrown down, the job of
rebuilding them is apt to seem hopeless.”
“That is where it will hit Phil the hardest, I’m sure. But we won’t
hope for the worst. Are you stopping over for a few days?”
“Until Monday or Tuesday. Are your quarters here in the Windsor?”
“Oh, no; I have a boarding place in West Denver—with friends. I’m
here just now to call upon some other friends—people from
Philadelphia. And that reminds me: you said you used to live in
Philadelphia; perhaps you know these friends of mine—the
Follansbees?”
“Not Judge John?”
“You have called the turn; Judge John and Mrs. Judge John and Tom
and Eugenia and Lucy Ann.”
“You don’t tell me! I know the judge and his wife very well, indeed;
and the children, too, though they were only children in my time.
You say they are here, in the hotel?”
“Yes. Wait a minute and I’ll carry the word to them.”
He was gone only a short time, and when he returned to the lobby,
the judge and Mrs. Follansbee came with him. He stood aside while
the three were happily bridging the gap of the years, and at the first
lull he broke in smoothly to say to Drew: “Mrs. Follansbee has been
good enough to include me in a dinner party for this evening, and I
have just told her that I am unexpectedly obliged to leave town, but
I was quite sure you would be willing to substitute for me.”
“Of course you will, Stephen,” put in the lady patroness, surveying
the stocky figure of the promoter through her lorgnette; then, with a
sigh for the vanished years: “My, my; what a man you’ve grown to
be! I should never have known you, with that clipped beard and the
eyeglasses. Can’t you spare a few minutes to come up to our suite
and see Eugenia and Lucy Ann? They both remember you.”
Bromley glanced at his watch and slipped away. He had promised to
take Jean Dabney to luncheon, and there was barely time to reach
Madame Marchande’s place in Sixteenth Street by the appointed
noon hour. When he did reach the millinery shop he found Jean
waiting on the sidewalk for him, and he took her to a new chop
house lately opened in the block next to the St. James, steering
clear of the subject that was uppermost in his mind until after they
were seated in one of the box-like private stalls and their order had
been given and served. Then he began without preface.
“I want to ask you something about Philip, Jean. He walked home
with you a week ago last Monday evening, didn’t he?”
“Let me think,” she answered reflectively. “To-day is Saturday; yes, it
was a week ago Monday.”
“Did he—did he act as though he was especially troubled about
anything?”
“Why, no; not that I saw. I remember he scolded me a little because
he seemed to think I wasn’t quite as savagely righteous as I ought
to be. But he has done that lots of times. He walks so straight
himself that he can’t bear to see anybody lean over, ever so little.”
Bromley winced. If Drew’s story were true—and there was no reason
to doubt it—Philip was not walking straight now; he was grovelling.
What would Jean say if she knew? He had not meant to tell her
what he had just heard; did not yet mean to tell her. Still, she would
have to know, some time. If he could only be sure that the
knowledge wouldn’t smash her.... He would have to feel his way
carefully.
“I am wondering if Philip ever told you anything about his father,” he
said; and he tried to say it casually.
“Oh, yes; he has told me all there was to tell, I think: how his father
went away under a—under a cloud, and how he has been searching
for him out here. Was that what you meant?”
Bromley nodded. There was nothing in her tone or manner to lead
him to believe that she had anything more than a friendly interest in
Philip’s problem, and he went on.
“He has been away for two weeks, or nearly two weeks. He left
town the next morning after he walked home with you that Monday
evening. He didn’t tell me where he was going. Did he tell you?”
“He said he might go to the camps down in the San Juan next. But
he didn’t say anything about going so soon. Haven’t you heard from
him since that time?”
“No; he hasn’t written me,” Bromley hastened to say, telling a half-
truth which was little short of a lie direct.
“But you are not anxious about him, are you?”
“Anxious? Why should I be?”
“But I think you are,” she said, looking him fairly in the eyes.
As upon certain other occasions, he tried hard to plumb the depths
of the dark eyes that were lifted to his, striving to read the answer
to a question that had been tormenting him ever since his first
meeting with her. How much did she care for Philip? Was she as
much in love with him as he was with her? If she were, this was
neither the time nor the place for the repeating of Drew’s story. But
if she were not ... he made up his mind suddenly and took the
plunge.
“Jean, you know you can trust me to the limit, don’t you? Tell me
honestly what there is between you and Philip.”
“What there is between us?” The steady gaze of the dark eyes did
not waver. “We are friends, of course; good friends, I hope.”
“Nothing more?”
“What more could there be?”
“Then I may talk to you just as I might to any other friend of his?”
“I don’t know why you shouldn’t.” Tone and manner both gave him
the assurance that he might go on; that there was nothing more
vital to be wounded than the friendship she had admitted.
“Something has happened to Philip. I lied to you a minute ago—said
I hadn’t heard from Phil. I haven’t, not directly; but Mr. Drew is
down from Leadville, and he tells me that Philip is up in the big
camp, ripping things wide open. I couldn’t believe it—can hardly
believe it yet.”
The deep-welled eyes were downcast now, and Bromley held his
breath. If there were a little quiver of the sensitive lips when she
spoke, the play-boy missed it—missed everything but the steady
tone of her reply.
“I have been afraid of something like that, haven’t you? Of course,
you know what has happened?”
“I don’t—I can’t imagine!”
“It is perfectly plain. He has found his father.”
“You think that is it?”
“I am sure of it.”
“But, even so—” he began.
“Don’t you see? He hasn’t—he didn’t find things as he hoped to find
them. Don’t you know him well enough to know what that would do
to him?”
It was said coolly enough, almost coldly; and Bromley marvelled. He
had never imagined she could be so dispassionate. Before he could
pull himself around to some half-way adequate matching of her
mood, she went on:
“Philip has always walked in a very narrow and straight path for
himself, and he is very proud, in his own way. If something has
happened to break his pride.... I know that is what has happened; I
am sure of it.”
The play-boy drew a deep breath. The worst was over, and it wasn’t
nearly as bad as he had feared it would be. Either she didn’t care,
any more than a friendly soul should care, or she had more
adamantine self-control than had fallen to the share of any other
woman he had ever known.
“I’m going up after him to-night,” he said. “When I get him back
here you’ll have to help me.”
“Of course—if I can,” she agreed. “But if it is as I think it is, I’m
afraid neither of us will be able to help him very much.”
“Why do you say that?”
“Just because he is what he is. Some people have to be helped; they
can’t get up unless they are helped. But there are others—and Philip
is one of them—who have to fight their way back the best they can,
alone. It’s hard to think of it that way, for a—for a friend. But it is
true.”
Bromley forced himself to smile.
“You are a very wise little woman, much wiser than your years call
for. But see here—you’re not eating enough to keep a kitten alive.
How do you expect to be able to work if you don’t eat?”
“I’m not as hungry as I thought I was. It’s the hot weather, maybe.”
“Couldn’t you eat another cream puff if I should order it?”
“No, thank you. Besides, my time is up. I know it isn’t nice to eat
and run, but if you will invite a working girl out to luncheon, you’ll
have to take the consequences.”
He walked back to the door of the millinery shop with her and at the
moment of parting she said, “You’ll be gentle with Philip when you
find him, won’t you? It won’t do any good to be the other way.”
“I shall take him by the neck,” he threatened good-naturedly,
adding: “He’s old enough and man enough to have better sense.”
Then: “I’m going to be fearfully busy this afternoon. Do you suppose
Mysie could pack my grip for me if I should send a messenger after
it with a note?”
“Mysie would be dreadfully humbled if she could hear you ask such a
thing as that,” she smiled. “She isn’t the child you seem to persist in
believing her to be. She will be sixteen in a few days. How long do
you think you will be away?”
“Heaven knows; no longer than I can help, you may be sure. Good-
by; take care of yourself, and don’t work too hard. If you want to do
anything for me while I’m gone, just say a little prayer or two. It
runs in my mind that I may need all the help I can get. Good-by.”
Having become, in a desultory way, a working capitalist, or at least
an investing one, Bromley had a number of business matters to be
despatched before he could leave town for an indefinite stay. None
the less, out of a well-filled afternoon he clipped time enough to go
around to the Colorado National Bank where Philip kept his account.
Since he was known in the bank as Philip’s partner, he had no
difficulty in finding out what he wished to learn. Philip had been
drawing heavily on his checking account during the two weeks, and
the drafts had all come through Leadville banks. Bromley asked for
the approximate figure and gasped when he was told that the recent
withdrawals totalled something over twenty thousand dollars.
Quartered in the sleeper for the night run to Leadville, Bromley,
generously distressed, was still groping for some reasonable solution
to the problem presented by Philip’s wild splash into the sea of
dissipation—a plunge so wholly out of keeping with his character.
Was Jean’s guess that he had found his father, and that the
discovery had proved to be a calamity instead of a cause for
rejoicing, the right one? If not, what other upsetting thing could
have happened between half-past seven in the Monday evening,
when he had left Philip in their common sitting-room in the Alamo
Building, and the next morning when he had met him leaving the
breakfast-table in Charpiot’s? Where had Philip spent the night? And
what had occurred during those few unaccounted-for hours to put a
look of morbid gloom in his eyes and to make him refuse, almost
savagely, to become an inmate of the West Denver cottage?
“He’d had a knock-down fight of some sort with that strait-laced
conscience of his, I suppose, and it must have been a bloody one to
make him let go all holds like this,” the play-boy told himself,
balancing on the edge of the made-down berth to take off his shoes
as the train began its swaying, wheel-shrilling climb in the snake-like
sinuosities of Platte Canyon. Then, as he drew the curtains and
essayed the irritating task of undressing in the dark, cramped berth,
with the car careening to right and left like a ship at sea: “He’ll find
it bad medicine and bitter; but if it will only end by making a normal
human man of him....”
It was deep in the night, and the train was halted at a mountain-side
station, when Bromley awoke, shivering in the chill of the high
altitude, and sat up to reach for the extra blanket at the foot of the
berth. As he did so, a thunderous murmur in the air announced the
approach of the Denver-bound train for which his own was side-
tracked, and he ran a window shade up to look out just as the
eastbound train, with its miniature locomotive and short string of
cars, coasted down, with brake-shoes grinding, to the meeting-point
stop.
Reflecting upon it afterward, he thought it a most curious
coincidence that the night chill should have awakened him just at
this time, and that the momentary stop of the opposing train should
place the one pair of lighted windows in its single Pullman opposite
his own darkened one. While one might have counted ten he sat
staring, wide-eyed, across the little space separating the two
standing trains. The lighted windows opposite were those in the
smoking compartment of the eastbound sleeper. Around the little
table bracketed between the seats sat three men with cards in their
hands and stacks of red, white and blue counters before them.
Though two of the men were unknown to the play-boy, he was able
instantly to label them as birds of prey. The third man was Philip; a
Philip so changed and wasted by two weeks of unrestraint as to be
scarcely recognizable.
As Bromley looked he saw one of the birds of prey pass a flat pocket
bottle across the table; and his final glimpse through the lighted
window as the down train slid away showed him Philip with his head
thrown back and the tilted bottle at his lips.
“Good Lord!” groaned the play-boy, falling back upon his pillows,
“Drew didn’t stretch it an inch! Those two blacklegs will strip Phil to
the skin before they let go of him and before they will let him get
sober enough to realize what they’re doing to him! And I’ve got to
go through to Leadville and come all the way back before I can get a
chance to stick my oar in!” At the word the westbound train began
to move, and he pulled the blankets up to his ears, muttering again:
“There’s only one ray of comfort in the whole desperate business,
and that is that Jean isn’t going to break her heart over this diabolic
blow-up of Philip’s. I’m glad I took the trouble to make sure of that,
anyhow.”
But if, at this precise moment of midnight, he could have looked into
the bed-room next to his own in the West Denver cottage, the room
occupied by Jean and her sister Mysie, the comforting reflection
might have lost something of its force. The younger sister was
sleeping peacefully, but the elder had slipped quietly out of bed to
kneel at the open, westward-fronting window with her shoulders
shaking and her face buried in the crook of a bare white arm.
XIX
Though Bromley, swiftly changing from the up to the down train on
the Sunday morning arrival in Leadville, should have won back to
Denver at six o’clock Sunday evening, a freight wreck on the
Kenosha Mountain grade held him up, and it was between nine and
ten when, tired as he was by more than twenty-four hours of
mountain railroad travel, he set out in search of Philip, making the
rooms of the Alamo Building his starting point.
To his relief, the lighted transom assured him that the sitting-room
was occupied; and when there was no answer to his knock, he
opened the door noiselessly and entered. At first he thought the
hunched figure in the hollowed-out easy chair beside the reading
table was in a drunken stupor; but when he drew nearer he saw that
the fancied stupor was merely a deep sleep of exhaustion. Silently
placing a chair for himself on the other side of the table, he lighted
his pipe and waited. After a time the sleeper in the hollowed chair
stirred, stretched his arms over his head, and, at the smell of live
tobacco smoke, opened his eyes and sat up with a jerk.
“You?” he muttered, blinking across the table at the play-boy.
“It’s nobody else. Had a good nap?”
Philip’s wordless response was to get up and reach for a half-
emptied bottle standing on a bookcase; but Bromley stopped him.
“Let that alone, Phil—for the moment, anyway; long enough to tell
me what has hit you. You owe me that much, at least.”
Philip sank back into the sleepy-hollow chair. “How much do you
know?” he demanded sullenly.
“What Stephen Drew could tell me, added to what I happened to
see at midnight last night when your train on the South Park met
mine at the passing point in the mountains.”
“You were going to Leadville to hunt me up?”
“Yes. Drew told me you needed to be knocked down and dragged
out.”
Philip’s dull eyes glowed suddenly. “I ought to have had a gun last
night!” he broke out savagely. “Those two tinhorns robbed me
blind!”
“Of course they did. That is what they were out for. No, wait; I’m not
going to preach. I grant you it’s every man’s privilege to go to the
devil in his own fashion. Still, I’m a trifle curious.”
Silence for the space of a long minute. Then: “You wouldn’t
understand, Harry; I couldn’t make you understand if I should try.
Say that the cursed atmosphere of this God-forsaken country got
hold of me at last and that I stubbed my toe and fell down. That will
cover it as well as anything.”
“A good many of us fall down, but we get up again. Have you got to
stay down?”
“It looks that way. I haven’t anything to get up for.”
“Why haven’t you?”
“That question runs you up against a shut door, Harry; a door that
I’ll never open for anybody so long as I can keep it shut. Let that be
understood, once for all.”
“All right; we’ll let it go at that, if you say so. Just the same——”
“Well?”
“Oh, confound it—you know what I want to say, and can’t Phil!
You’ve been more than a brother to me, ever since you picked me
up out of the gutter a year ago and stood me on my two feet. Can’t
you see where this thing hits me?”
Philip leaned forward, elbows on knees, face propped in his hands,
lead-heavy eyes fixed upon the blank wall opposite. When he
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

textbookfull.com

You might also like