Skip to content

Commit 4f61e6a

Browse files
authored
Merge pull request #383 from Xronophobe/csanad--review-chapter-27
Csanád's review of chapter 27 and the AI Preface
2 parents 6aabd01 + b2480d7 commit 4f61e6a

File tree

1 file changed

+45
-6
lines changed

1 file changed

+45
-6
lines changed

chapter_27_hot_lava.asciidoc

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ and the end of our journey with this to-do app and its tests.
1111
Let's recap our test structure so far:
1212

1313
* We have a suite of functional tests that use Selenium to test that the whole app really works.
14-
On several occasions, the FTs have saved us from shipping broken code—whether it was broken CSS, a broken database due to filesystem permissions, or broken email integration.
14+
On several occasions, the FTs have saved us from shipping broken code--whether it was broken CSS,
15+
a broken database due to filesystem permissions, or broken email integration.
1516

1617
* And we have a suite of unit tests that use Django test client, enabling us to test-drive our code for models, forms, views, URLs, and even (to some extent) templates.
1718
They've enabled us to build the app incrementally, to refactor with confidence,
@@ -250,11 +251,23 @@ Functional/end-to-end tests::
250251
including all dependencies and connected external systems.
251252
An FT is the ultimate test that it all hangs together,
252253
and that things are "really" going to work.
253-
254+
// CSANAD: I find the expression 'things are "really" going to work' too vague.
255+
// I would rather mention User Stories here, since they very often can be turned into
256+
// functional/end-to-end tests: they are worded similarly and they both cover specific
257+
// functionalities that are valuable for a given user (edit: well, you talk
258+
// about this below, under "On Acceptance Tests").
259+
// Furthermore, I would maybe give an example for each:
260+
// "Francis starts a new list by entering a new item."
254261

255262
Integration tests::
256263
The purpose of an integration test should be to check that the code
257264
you write is integrated correctly with some "external" system or dependency.((("integration tests")))
265+
// CSANAD: this one is more tricky to find integration tests for, since we
266+
// didn't create separate 'integration tests'. Maybe an example could be
267+
// checking whether Bootstrap is loaded correctly, or perhaps the email.
268+
// Something like that would be helpful in my opinion, especially because
269+
// we promised in Chapter 05 ("Unit Tests Versus Integration Tests, and the Database")
270+
// that we would further clarify the difference.
258271

259272

260273
(True) unit tests::
@@ -263,10 +276,16 @@ Integration tests::
263276
The ideal unit test is fully isolated((("unit tests")))
264277
from everything external to the unit under test,
265278
such that changes to things outside cannot break the test.
279+
// CSANAD: I was trying to find an example of a pure unit test. I recall
280+
// we may have had some helper function at some point, for which there was
281+
// no need to use Django's TestCase but I can't find it. Maybe I'm
282+
// remembering wrong.
266283

267284
The canonical advice is that you should aim to have the majority of your tests
268285
be unit tests, with a smaller number of integration tests,
269286
and an even smaller number of functional tests—as in the classic "test pyramid" of <<test_pyramid>>.
287+
// CSANAD: in the HTML, it read: "as in the classic 'Test Pyramid' of The Test Pyramid".
288+
270289

271290
[[test_pyramid]]
272291
.The test pyramid
@@ -291,6 +310,10 @@ Top layer: a minimal set of functional/end-to-end tests::
291310
But because they are the slowest and most brittle,
292311
we want as few of them as possible.
293312

313+
// CSANAD: I think explaining the layers after having explained the types of
314+
// tests just above it, seems a little redundant. I wonder if we should combine
315+
// them.
316+
294317

295318
[[acceptance_tests]]
296319
.On Acceptance Tests
@@ -338,6 +361,8 @@ Ed Jung calls this https://oreil.ly/sm16H[Mock Hell].
338361
This isn't to say that mocks are always bad!
339362
But just that, from experience,
340363
attempting to use them as your primary tool for decoupling
364+
// CSANAD: I think we could actually argue that by using mocks, we
365+
// accept that the code is tightly coupled with its dependencies.
341366
your tests from external dependencies is not a viable solution;
342367
it carries costs that often outweigh the benefits.
343368

@@ -350,8 +375,9 @@ NOTE: I'm glossing over the use of mocks in a London-school
350375

351376
The actual solution to the problem isn't obvious from where we're standing. It lies in rethinking the architecture of our application.((("architectures of applications")))
352377
In brief, if we can _decouple_ the core business logic of our application
353-
from its dependencies, then we can write true unit tests for it
354-
that do not depend on those, um, dependencies.((("business logic, decoupling from dependencies")))((("dependencies", "decoupling business logic from")))
378+
from its dependencies, then we can write true, isolated unit tests for it
379+
that do not depend on those, um, dependencies.
380+
((("business logic, decoupling from dependencies")))((("dependencies", "decoupling business logic from")))
355381

356382
Integration tests are most necessary at the _boundaries_ of a system--at
357383
the points where our code integrates with external systems—like the database, filesystem, network, or a UI.((("boundaries between system components", "integration tests and")))
@@ -389,7 +415,14 @@ call this approach "Ports and Adapters" (see <<ports-and-adapters>>).
389415
.Ports and Adapters (diagram by Nat Pryce)
390416
image::images/tdd3_2702.png["Illustration of ports and adapaters architecture, with isolated core and integration points"]
391417

392-
This pattern, or variations of it, are known as
418+
419+
// CSANAD: I haven't found the original diagram by Nat Pryce. I would recommend
420+
// maybe a making the next header "Functional Core, Imperative Shell" formatted
421+
// differently, making it more obvious that it's an explanation of the diagram.
422+
// Or, we could just add a "Legend" under the diagram, explaining what the
423+
// nodes, arrows and different shades of the layers depict.
424+
425+
This pattern, or variations on it, are known as
393426
"Hexagonal Architecture" (by Alistair Cockburn),
394427
"Clean Architecture" (by Robert C. Martin, aka Uncle Bob),
395428
or "Onion Architecture" (by Jeffrey Palermo).
@@ -535,7 +568,7 @@ What that means is that some of the more advanced uses of TDD,
535568
particularly the interplay between testing and architecture,
536569
have been beyond the scope of this book.
537570

538-
But I hope that this chapter has been a bit a guide to find your way
571+
But I hope that this chapter has been a bit of a guide to find your way
539572
around that topic as your career progresses.
540573

541574
[role="pagebreak-before less_space"]
@@ -589,3 +622,9 @@ A take from the world of functional programming::
589622
_Grokking Simplicity_ by Eric Normand
590623
explores the idea of "Functional Core, Imperative Shell".
591624
Don't worry; you don't need a crazy functional programming language like Haskell or Clojure to understand it—it's written in perfectly sensible JavaScript.
625+
// CSANAD: Shouldn't we provide a link to this book too?
626+
// https://www.oreilly.com/library/view/grokking-simplicity/9781617296208/
627+
// O'Reilly resources usually have a different kind of link though.
628+
629+
630+
Happy testing!

0 commit comments

Comments
 (0)