Skip to content

Commit 582ab6e

Browse files
authored
Merge branch 'hjwp:main' into chapter-11-notes-starting-from-upstream
2 parents ec0746d + 23ef0da commit 582ab6e

15 files changed

+327
-122
lines changed

ER_sampleTOC.html

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<section data-type="preface">
2+
<h1>Brief Table of Contents (<em>Not Yet Final</em>)</h1>
3+
4+
<p>Preface (AVAILABLE)</p>
5+
<p>Prerequisites and Assumptions (AVAILABLE)</p>
6+
<p>Companion Video (AVAILABLE)</p>
7+
<p><em>Acknowledgments (UNAVAILABLE)</em></p>
8+
<p>Part 1: The Basics of TDD and Django (AVAILABLE)</p>
9+
<p>Chapter 1: Getting Django Set Up Using a Functional Test (AVAILABLE)</p>
10+
<p>Chapter 2: Extending Our Functional Test Using the unittest Module (AVAILABLE)</p>
11+
<p>Chapter 3: Testing a Simple Home Page with Unit Tests (AVAILABLE)</p>
12+
<p>Chapter 4: What Are We Doing with All These Tests? (And, Refactoring) (AVAILABLE)</p>
13+
<p>Chapter 5: Saving User Input: Testing the Database (AVAILABLE)</p>
14+
<p>Chapter 6: Improving Functional Tests: Ensuring Isolation and Removing Voodoo Sleeps (AVAILABLE)</p>
15+
<p>Chapter 7: Working Incrementally (AVAILABLE)</p>
16+
<p>Part 2: Web Development Sine Qua Nons (AVAILABLE)</p>
17+
<p>Chapter 8: Prettification: Layout and Styling, and What to Test About It (AVAILABLE)</p>
18+
<p>Chapter 9: Deployment Part 1: Containerization akaDocker (AVAILABLE)</p>
19+
<p>Chapter 10: Getting to a Production-Ready Deployment (AVAILABLE)</p>
20+
<p>Chapter 11: Infrastructure As Code: Automated Deployments With Ansible (AVAILABLE)</p>
21+
<p><em>Chapter 12: Splitting Our Tests into Multiple Files, and a Generic Wait Helper (UNAVAILABLE)</em></p>
22+
<p><em>Chapter 13: Validation at the Database Layer (UNAVAILABLE)</em></p>
23+
<p><em>Chapter 14: A Simple Form (UNAVAILABLE)</em></p>
24+
<p><em>Chapter 15: More Advanced Forms (UNAVAILABLE)</em></p>
25+
<p><em>Chapter 16: Dipping Our Toes, Very Tentatively, into JavaScript (UNAVAILABLE)</em></p>
26+
<p><em>Chapter 17: Deploying Our New Code (UNAVAILABLE)</em></p>
27+
<p><em>Part 3: More Advanced Topics in Testing (UNAVAILABLE)</em></p>
28+
<p><em>Chapter 18: User Authentication, Spiking, and De-Spiking (UNAVAILABLE)</em></p>
29+
<p><em>Chapter 19: Using Mocks to Test External Dependencies or Reduce Duplication (UNAVAILABLE)</em></p>
30+
<p><em>Chapter 20: Test Fixtures and a Decorator for Explicit Waits (UNAVAILABLE)</em></p>
31+
<p><em>Chapter 21: Server-Side Debugging (UNAVAILABLE)</em></p>
32+
<p><em>Chapter 22: Finishing “My Lists”: Outside-In TDD (UNAVAILABLE)</em></p>
33+
<p><em>Chapter 23: Test Isolation, and “Listening to Your Tests” (UNAVAILABLE)</em></p>
34+
<p><em>Chapter 24: Continuous Integration (CI) (UNAVAILABLE)</em></p>
35+
<p><em>Chapter 25: The Token Social Bit, the Page Pattern, and an Exercise for the Reader (UNAVAILABLE)</em></p>
36+
<p><em>Chapter 26: Fast Tests, Slow Tests, and Hot Lava (UNAVAILABLE)</em></p>
37+
<p><em>Back Matter: Obey the Testing Goat! (UNAVAILABLE)</em></p>
38+
<p><em>App A: PythonAnywhere (UNAVAILABLE)</em></p>
39+
<p><em>App B: Django Class-Based Views (UNAVAILABLE)</em></p>
40+
<p><em>App C: Provisioning with Ansible (UNAVAILABLE)</em></p>
41+
<p><em>App D: Testing Database Migrations (UNAVAILABLE)</em></p>
42+
<p><em>App E: Behaviour-Driven Development (BDD) (UNAVAILABLE)</em></p>
43+
<p><em>App F: Building a REST API: JSON, Ajax, and Mocking with JavaScript (UNAVAILABLE)</em></p>
44+
<p><em>App G: Django-Rest-Framework (UNAVAILABLE)</em></p>
45+
<p><em>App H: Cheat Sheet (UNAVAILABLE)</em></p>
46+
<p><em>App I: What to Do Next (UNAVAILABLE)</em></p>
47+
<p><em>App J: Source Code Examples (UNAVAILABLE)</em></p>
48+
<p><em>Bibliography (UNAVAILABLE)</em></p>
49+
50+
</section>

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ build: $(HTML_PAGES) $(TMPDIR)
5252

5353
.PHONY: install
5454
install: .venv/bin
55-
which brew && brew install asciidoctor || apt install -y asciidoctor
55+
which brew && brew install asciidoctor tree || apt install -y asciidoctor tree
5656

5757
.PHONY: update-submodules
5858
update-submodules:

chapter_08_prettification.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ Here are a few things we might want:
8888
// including Django documentation or learnpython.org
8989
// Both look completely different today - not so ugly anymore
9090

91-
* A nice large input field for adding new and existing lists
91+
* A nice large input field for adding to new and existing lists
9292
* A large, attention-grabbing, centered box to put it in
9393

9494
((("aesthetics, testing", seealso="design and layout testing")))

chapter_09_docker.asciidoc

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ and this is a very new draft.
6161
What that means is that I'd, really, really love feedback from readers.
6262
Please have a go at following along and let me know what you think!
6363
I'm [email protected], or you can open up
64-
https://github.com/hjwp/Book-TDD-Web-Dev-Python/issues[GitHub Issue]
64+
https://github.com/hjwp/Book-TDD-Web-Dev-Python/issues[GitHub Issues]
6565
or Pull Requests.
6666
6767
Let me know how you got on, if you get stuck on anything,
@@ -861,6 +861,7 @@ The docker daemon lets you list all the currently running containers
861861
with `docker ps`:
862862
863863
[role="skipme small-code"]
864+
[subs="quotes"]
864865
----
865866
$ *docker ps*
866867
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
@@ -873,8 +874,9 @@ and a randomly-generated name (you can override that if you want to).
873874
We can use the ID or the name to kill the container with `docker kill`:
874875
875876
[role="skipme"]
877+
[subs="quotes"]
876878
----
877-
$ docker kill 0818e1b8e9bf
879+
$ *docker kill 0818e1b8e9bf*
878880
0818e1b8e9bf
879881
----
880882
@@ -904,7 +906,7 @@ What's going on here? Time for a little debugging.
904906

905907

906908

907-
=== Debugging a Container Networking Problems
909+
=== Debugging Container Networking Problems
908910

909911
First, let's try and take a look ourselves, in our browser, by going to http://localhost:8888/:
910912

@@ -955,7 +957,9 @@ Starting development server at http://127.0.0.1:8888/
955957

956958
A quick run of the FT or check in our browser will show us that nope, that doesn't work either.
957959
Let's try an even lower-level smoke test, the traditional Unix utility `curl`.
958-
It's a command-line tool for making HTTP requests. Try it on your own computer first:
960+
It's a command-line tool for making HTTP requests.footnote:[
961+
`curl` can do FTP and many other types of network requests too! Check out the https://man7.org/linux/man-pages/man1/curl.1.html[curl manual].]
962+
Try it on your own computer first:
959963

960964
[role="ignore-errors"]
961965
[subs="specialcharacters,macros"]
@@ -1484,7 +1488,7 @@ Tests and small steps take some of the uncertainty out of deployment::
14841488
14851489
Some typical pain points--networking, ports, static files, and the database::
14861490
Moving from the local django development server to a container
1487-
is chance to rehearse the fiddliness of configuring networking
1491+
is a chance to rehearse the fiddliness of configuring networking
14881492
in a deployed environment.
14891493
It's also a chance to think about persistence and the database,
14901494
and some configuration issues like static files.

chapter_10_production_readiness.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@ RUN addgroup --system nonroot && adduser --system --group nonroot
800800
801801
USER nonroot
802802
----
803+
====
803804

804805

805806
=== Configuring logging

chapter_11_ansible.asciidoc

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ ______________________________________________________________
66
Automate, automate, automate.
77
______________________________________________________________
88

9+
.A Note for Early Release Readers
10+
****
11+
With Early Release ebooks, you get books in their earliest form—the author's raw and unedited content as they write—so you can take advantage of these technologies long before the official release of these titles.
12+
13+
This will be the 11th chapter of the final book. The GitHub repo is available at https://github.com/hjwp/book-example.
14+
15+
If you have comments about how we might improve the content and/or examples in this book, or if you notice missing material within this chapter, please reach out to the author at [email protected].
16+
****
17+
918
// RITA: In this intro, please mention that you'll be using Ansible. Not only will it prep the reader, but it'll set you up to say "(or "become" in Ansible terminology)" in the User Accounts, SSH, and Privileges section before we actually get to the Ansible section.
1019
((("deployment", "automating with Ansible", id="Dfarbric11")))
1120
((("infrastructure as code")))
@@ -17,6 +26,14 @@ We _could_ do all these things manually,
1726
but a key insight of the modern infrastructure management
1827
is that automation really pays off in reducing maintenance burdens.
1928

29+
// SEBASTIAN: IMO, above statement is not strong enough (my opinion)
30+
// I'd add something that software development nowadays is made in short cycles with frequent deployments
31+
// and automation is a MUST - the earlier one invests into it, the faster they can focus on doing what's
32+
// actually giving value.
33+
//
34+
// ALSO... to reassure readers - automating anything requires deep understanding, so they will not miss anything.
35+
// Perhaps this is even more important. When I first read this, I was like "ohhh, I'm gonna miss some fun!"
36+
2037
It's also key to making sure our tests give us true confidence over our deployments.
2138
If we go to the trouble of building a staging server,footnote:[
2239
What I'm calling a "staging" server, some people would
@@ -67,9 +84,26 @@ A few small things:
6784
billed needlessly.
6885
////
6986

87+
////
88+
SEBASTIAN overall notes
89+
All in all, I am not very fond of the current shape of this chapter.
7090
71-
.🚧 Warning, chapter under construction 🚧
72-
*******************************************************************************
91+
The summary is great and the choice of technologies is the best I can imagine.
92+
93+
However, I got lost several times while reading through the chapter.
94+
There are too many open loops. For example, SSH is mentioned but then we jump into all other technologies without seeing what SSH is and how it will play with the rest.
95+
96+
mentioning of too many technologies (e.g. Puppet/Chef - IMHO not necessary in 2024).
97+
98+
I think (my opinion) the chapter needs reorganizing so that readers can more quickly see a given piece of tech in action. I'd cut some content.
99+
100+
If you like some more specific suggestions, I can spend more time and provide them.
101+
102+
Also, it's mentioned that the server will be provisioned manually without automation, but then we get ansible infra/ansible-provision.yaml. I must say I'm not following when provisioning starts and where it ends. In my book (figuratively speaking), installing docker falls under the definition of provisioning (which was meant NOT to be automated) while the remaining steps, like exporting and reimporting docker image are something different (deployment?).
103+
////
104+
105+
.Warning, chapter under construction
106+
****
73107
As part of my work on the third edition of the book,
74108
I'm making big changes to the deployment chapters.
75109
This chapter is still very fresh, but the content is all there,
@@ -81,8 +115,7 @@ https://github.com/hjwp/Book-TDD-Web-Dev-Python/issues[GitHub Issues]
81115
and Pull Requests.
82116
83117
I hope you enjoy the new version!
84-
85-
*******************************************************************************
118+
****
86119

87120

88121
=== Getting a Domain Name
@@ -152,6 +185,7 @@ They're unlikely to ever go away,
152185
and knowing a bit about them will get you some respect
153186
from all the grizzled dinosaurs out there.
154187

188+
// SEBASTIAN: Nice, and seem-to-be timeless choice!
155189

156190

157191
==== Spinning Up a Server
@@ -309,10 +343,10 @@ rather than specifying a procedural series of steps to be followed one by one.
309343

310344
==== Installing Ansible
311345

312-
Take a look at the https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html [documentation] for instructions on how to install Ansible.
313-
// RITA: Please anchor all URLs to descriptive text.
314-
315-
The simplest thing to do is to install Ansible into the virtualenv
346+
Take a look at the
347+
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html[Ansible installation guide]
348+
for all the various options,
349+
but probably the simplest thing to do is to install Ansible into the virtualenv
316350
on our local machine:
317351

318352
[subs="specialcharacters,quotes"]
@@ -908,6 +942,11 @@ but I wanted to keep this (already long) chapter as simple as possible.
908942
*******************************************************************************
909943

910944

945+
// SEBASTIAN: I feel the above section would make more sense if it was mentioned waaay earlier.
946+
// I must say I got lost while reading about Chef, Puppet and suddenly I see some Ansible examples
947+
// without any explanation how Ansible works, any diagrams etc.
948+
// I'd also appreciate seeing some example of SSH first as this is a prerequisite to
949+
// using Ansible. Currently, there are too many "open loops" and I think this chapter is hard to follow.
911950

912951
Let's run the latest version of our playbook and see how our tests get on:
913952

@@ -971,6 +1010,8 @@ selenium.common.exceptions.WebDriverException: Message: Reached error page:
9711010
about:neterror?e=connectionFailure&u=http%3A//staging.ottg.co.uk/[...]
9721011
----
9731012

1013+
// SEBASTIAN: It's awesome that by this moment by using `TEST_SERVER` one is able to run tests against "staging". Just wow!
1014+
9741015

9751016
That `neterror` makes me think it's another networking problem.
9761017

@@ -1397,9 +1438,15 @@ which are a fairly typical set of steps for deployment in general
13971438
and looking into techniques like red-green deployments.
13981439
// CSANAD: we haven't mentioned the downtime so far
13991440
1441+
// SEBASTIAN: Is red-green deployment a thing? I must admit it's the first time
1442+
// I see the name and so far I've only know blue-green. I also read there's red-black deployment,
1443+
// but am I looking for this wrong, so I cannot find anything about red-green? 🤔
1444+
14001445
// TODO is there a better word than "switching across"?
14011446
// CSANAD: I can only think of "releasing" or "deploying"
14021447
1448+
// SEBASTIAN: How about simply "updating" or "changing"?
1449+
14031450
Every single aspect of deployment can and probably should be automated.
14041451
Here are a couple of general principles to think about
14051452
when implementing infrastructure-as-code:
@@ -1415,5 +1462,6 @@ Declarative::
14151462
rather than _how_ we should get there.
14161463
This goes hand-in-hand with the idea of idempotence above.
14171464
1465+
// SEBASTIAN: Okay, this summary is goldie 👌
14181466
14191467
*******************************************************************************

chapter_12_organising_test_files.asciidoc

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
[[chapter_12_organising_test_files]]
22
== Splitting Our Tests into Multiple Files, and a Generic Wait Helper
33

4-
.🚧 Warning, chapter update in progress
5-
*******************************************************************************
6-
This chapter is currently in the process of being rewritten for the 3e.
7-
8-
The code listings should all be valid,
9-
and work with Python3.12 + Django 4,
10-
but I haven't reviewed the chapter text in detail yet.
11-
12-
*******************************************************************************
134

145
Back to local development!
156
The next feature we might like to implement is a little input validation.
@@ -62,6 +53,9 @@ def test_cannot_add_empty_list_items(self):
6253
----
6354
====
6455

56+
// DAVID: I think we should spell out that you want us to add this to the test file. Also,
57+
// where? As a method of NewVisitorTestCase?
58+
6559
That's all very well, but before we go any further--our
6660
functional tests file is beginning to get a little crowded.
6761
Let's split it out into several files, in which each has a single test method.
@@ -79,6 +73,8 @@ how to get there step by step.
7973
NOTE: We're back to local development now.
8074
Double check that the `TEST_SERVER` environment variable is unset in your terminal.
8175

76+
// DAVID: might be nice to remind people how they check this?
77+
8278
((("unittest module", "skip test decorator")))
8379
((("refactoring")))
8480
((("decorators", "skip test decorator")))
@@ -98,6 +94,7 @@ from unittest import skip
9894
def test_cannot_add_empty_list_items(self):
9995
----
10096
====
97+
// DAVID: The indentation here looks weird - maybe better to include the class declaration too?
10198

10299
This tells the test runner to ignore this test.
103100
You can see it works--if we rerun the tests,
@@ -171,6 +168,10 @@ https://www.oreilly.com/library/view/tidy-first/9781098151232/[Tidy First?]
171168
((("test files", "splitting FTs into many")))
172169
We start putting each test into its own class, still in the same file:
173170

171+
// DAVID: I would say this is too big a refactor all in one go.
172+
// A nicer way to do this would be to break out the base class first as one refactor, moving it into another file.
173+
// Then when we copy the files we could rename each class and delete the irrelevant methods.
174+
174175
[role="sourcecode"]
175176
.src/functional_tests/tests.py (ch11l002)
176177
====
@@ -204,6 +205,8 @@ class ItemValidationTest(FunctionalTest):
204205
----
205206
====
206207

208+
// DAVID: I also have check_for_row_in_list_table as a method - maybe I should've removed it?
209+
207210
At this point we can rerun the FTs and see they all still work:
208211

209212
----
@@ -383,6 +386,7 @@ when we're only interested in a single one.
383386
Although we need to remember to run all of them now and again, to check for regressions.
384387
Later in the book we'll set up a Continuous Integration (CI) server to run all the tests automatically,
385388
for example every time we push to master.
389+
// DAVID: "master" -> "our main branch"
386390
For now, a good prompt for running all the tests is "just before you do a commit",
387391
so let's get into that habit now:
388392

@@ -462,6 +466,8 @@ might decide that building a specific helper method is overkill at this stage,
462466
but it might be nice to have some generic way of saying, in our tests, "wait
463467
until this assertion passes". Something like this:
464468

469+
// DAVID: might be worth reminding the reader about that helper method, e.g. what it's called.
470+
465471
[role="sourcecode"]
466472
.src/functional_tests/test_list_item_validation.py (ch11l009)
467473
====
@@ -511,6 +517,8 @@ and we'll adapt it slightly:
511517
----
512518
====
513519

520+
// DAVID: I have `raise e` from that other method, not `raise`.
521+
514522
<1> We make a copy of the method, but we name it `wait_for`,
515523
and we change its argument. It is expecting to be passed a function.
516524

@@ -594,6 +602,9 @@ and that can be executed later, and multiple times:
594602

595603
Let's see our funky `wait_for` helper in action:
596604

605+
// DAVID: Might be worth explicitly telling the reader to add that code earlier - I hadn't yet,
606+
// so I have to go back and find the right snippet.
607+
597608
[subs="macros,verbatim"]
598609
----
599610
$ pass:quotes[*python src/manage.py test functional_tests.test_list_item_validation*]
@@ -861,6 +872,8 @@ Use a tests folder::
861872
* You probably want a separate test file for each tested source code
862873
file. For Django, that's typically 'test_models.py', 'test_views.py', and
863874
'test_forms.py'.
875+
// DAVID: worth mentioning that mirroring test files to real files can pave the way for automatically running tests
876+
// relevant to your changes.
864877
* Have at least a placeholder test for 'every' function and class.
865878
((("test files", "organizing and refactoring")))
866879
@@ -871,8 +884,15 @@ Don't forget the "Refactor" in "Red, Green, Refactor"::
871884
((("Red/Green/Refactor")))
872885
873886
Don't refactor against failing tests::
874-
* In general!
875-
* But the FT you're currently working on doesn't count.
887+
* The general rule is that you shouldn't mix refactoring and behaviour
888+
change. Having green tests is our best guarantee that we aren't changing
889+
behaviour. If you start refactoring against failing tests, it becomes much
890+
harder to spot when you're accidentally introducing a regression.
891+
* This applies strongly to unit tests. With functional tests, because we
892+
often develop against red FTs anyway, it's sometimes more tempting to
893+
refactor against failing tests. My suggestion is to avoid that temptation
894+
and use an early return, so that it's 100% clear if, during a refactory,
895+
you accidentally introduce a regression that's picked up in your FTs.
876896
* You can occasionally put a skip on a test which is testing something you
877897
haven't written yet.
878898
* More commonly, make a note of the refactor you want to do, finish what

0 commit comments

Comments
 (0)