Skip to content

Csanád's review of chapter 27 and the AI Preface #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 63 additions & 16 deletions chapter_27_hot_lava.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@
== Fast Tests, Slow Tests, and Hot Lava

[quote, 'https://www.youtube.com/watch?v=bsmFVb8guMU[Casey Kinsey]']
// CSANAD: "This video isn't available any more" :(
// Here is the official page for the talk, but it has no video or slides
// available:
// https://2013.djangocon.us/schedule/presentation/17/
//
// I found the slides on slideshare.net but I'm unsure about licensing. I saved
// the link but I'm not going to include it in the book's source yet. Let me
// know if it's legit and we can use the link!
// Maybe it would be better to reach out straight to Casey Kinsey or the
// DjangoCon US team if they can make at least the slides available somewhere.

______________________________________________________________
The database is Hot Lava!
______________________________________________________________
Expand All @@ -11,7 +22,7 @@ and the end of our journey with this To-Do app and its tests.
Let's recap our test structure so far:

* We have a suite of "functional tests" that use Selenium to test that the whole app really works.
On several occations, the FTs have saved us from shipping broken code,
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.

* And we have a suit of "unit tests" that use Django's test client,
Expand Down Expand Up @@ -209,7 +220,7 @@ Anything longer than a few seconds and you're going to let your attention wander
you context-switch, and the flow state is gone.
And the flow state is a fragile dream.
Once it's gone, it takes a long time to come back.footnote:[
Some people says it takes at least 15 minutes to get back into the flow state.
Some people say it takes at least 15 minutes to get back into the flow state.
In my experience, that's overblown,
and I sometimes wonder if it's thanks to TDD.
I think TDD reduces the cognitive load of programming.
Expand Down Expand Up @@ -260,11 +271,23 @@ Functional/End-to-end tests::
including all dependencies and connected external systems.
They are the ultimate test that it all hangs together,
and that things are "really" going to work.

// CSANAD: I find the expression 'things are "really" going to work' too vague.
// I would rather mention User Stories here, since they very often can be turned into
// functional/end-to-end tests: they are worded similarly and they both cover specific
// functionalities that are valuable for a given user (edit: well, you talk
// about this below, under "On Acceptance Tests").
// Furthermore, I would maybe give an example for each:
// "Francis starts a new list by entering a new item."

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


(True) Unit tests::
Expand All @@ -273,11 +296,17 @@ Integration tests::
The ideal unit test is fully isolated
from everything external to the unit under test
such that changes to things outside cannot break the test.
// CSANAD: I was trying to find an example of a pure unit test. I recall
// we may have had some helper function at some point, for which there was
// no need to use Django's TestCase but I can't find it. Maybe I'm
// remembering wrong.

The canonical advice is that you should aim to have the majority of your tests
be unit tests, with a smaller number of integration tests,
and an even smaller number of functional tests,
as in the classic "Test Pyramid" of <<test_pyramid>>.
as in <<test_pyramid>>.
// CSANAD: in the HTML, it read: "as in the classic 'Test Pyramid' of The Test Pyramid".
// I changed it, so now it's just "as in The Test Pyramid" to avoid repetition.

[[test_pyramid]]
.The Test Pyramid
Expand All @@ -302,6 +331,10 @@ Top Layer: A minimal set of Functional/End-to-End Tests::
But because they are the slowest and most brittle,
we want as few of them as possible.

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


[[acceptance-tests-sidebar]]
.On Acceptance Tests
Expand Down Expand Up @@ -352,6 +385,8 @@ Ed Jung calls this https://youtu.be/CdKaZ7boiZ4[Mock Hell].
This isn't to say that mocks are always bad!
But just that, from experience,
attempting to use them as your primary tool for decoupling
// CSANAD: I think we could actually argue that by using mocks, we
// accept that the code is tightly coupled with its dependencies.
your tests from external dependencies is not a viable solution;
it carries costs that often outweigh the benefits.

Expand All @@ -365,7 +400,7 @@ NOTE: I'm glossing over the use of mocks in a "London-school"
The actual solution to the problem isn't obvious from where we're standing,
but it lies in rethinking the architecture of our application.
In brief, if we can _decouple_ the core business logic of our application
from its dependencies, then we can write true unit tests for it,
from its dependencies, then we can write true, isolated unit tests for it,
that do not depend on those, um, dependencies.

Integration tests are most necessary at the _boundaries_ of a system--at
Expand Down Expand Up @@ -422,6 +457,12 @@ call this approach "Ports and Adapters" (see <<ports-and-adapters>>).
.Ports and Adapters (diagram by Nat Pryce)
image::images/twp2_2601.png["Illustration of ports and adapaters architecture, with isolated core and integration points"]

// CSANAD: I haven't found the original diagram by Nat Pryce. I would recommend
// maybe a making the next header "Functional Core, Imperative Shell" formatted
// differently, making it more obvious that it's an explanation of the diagram.
// Or, we could just add a "Legend" under the diagram, explaining what the
// nodes, arrows and different shades of the layers depict.

This pattern, or variations on it, are known as
"Hexagonal Architecture" (by Alistair Cockburn),
"Clean Architecture" (by Robert C. Martin, aka Uncle Bob),
Expand Down Expand Up @@ -497,6 +538,7 @@ aren't the be-all and end-all.
image::images/frog-in-a-pan-placeholder.png["An illustration of a frog being slowly boiled in a pan"]

* TODO: update image
// CSANAD: I like this placeholder :D

For small to medium-sized applications, as we've seen, the Django test runner
and the integration tests it encourages us to write are just fine.
Expand Down Expand Up @@ -550,7 +592,7 @@ What that's meant is that some of the more advanced uses of TDD,
particularly the interplay between testing and architecture,
have been beyond the scope of this book.

But I hope that this chapter has been a bit a guide to find your way
But I hope that this chapter has been a bit of a guide to find your way
around that topic as your career progresses.


Expand All @@ -562,24 +604,26 @@ Fast Test, Slow Test and Boundaries::
Gary Bernhardt's talks from Pycon
https://www.youtube.com/watch?v=RAxiiRPHS9k[2012] and
https://www.youtube.com/watch?v=eOYal8elnZk[2013]. His
http://www.destroyallsoftware.com[screencasts] are also well worth a look.
https://www.destroyallsoftware.com/screencasts/catalog[screencasts] are also well worth a look.

Inverting the Pyramid::
// CSANAD: This link no longer points to the testing pyramid and I couldn't
// find the original content.
http://watirmelon.com/tag/testing-pyramid/[A visual metaphor]
for what to do with a project like ours would end up,
with too many slow tests and not enough fast ones.

Integration tests are a scam::
J.B. Rainsberger has a
http://blog.thecodewhisperer.com/2010/10/16/integrated-tests-are-a-scam/[famous rant]
https://blog.thecodewhisperer.com/2010/10/16/integrated-tests-are-a-scam/[famous rant]
about the way integration tests will ruin your life.footnote:[
Rainsberger actually distinguishes "integrated" tests from integration tests:
integrated test is any test that's not fully isolated from things outside
the unit under test.[
the unit under test.]
Then check out a couple of follow-up posts, particularly
http://www.jbrains.ca/permalink/using-integration-tests-mindfully-a-case-study[this
https://blog.thecodewhisperer.com/permalink/using-integration-tests-mindfully-a-case-study[this
defence of acceptance tests], and
http://www.jbrains.ca/permalink/part-2-some-hidden-costs-of-integration-tests[this
https://blog.thecodewhisperer.com/permalink/part-2-some-hidden-costs-of-integrated-tests[this
analysis of how slow tests kill productivity].
((("integrated tests", "benefits and drawbacks of")))

Expand All @@ -588,9 +632,9 @@ Ports and Adapters::
You can also catch a good discussion in
http://vimeo.com/83960706[this talk].
See also
http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html[Uncle
https://blog.cleancoder.com/uncle-bob/2011/11/22/Clean-Architecture.html[Uncle
Bob's description of the clean architecture], and
http://alistair.cockburn.us/Hexagonal+architecture[Alistair Cockburn
https://alistair.cockburn.us/hexagonal-architecture[Alistair Cockburn
coining the term "hexagonal architecture"].

The Test-Double testing wiki::
Expand All @@ -601,15 +645,18 @@ The Test-Double testing wiki::


Fowler on Unit tests::
Martin Fowler (author of _Refactoring_)
http://martinfowler.com/bliki/UnitTest.html[balanced and pragmatic tour]
Martin Fowler's (author of _Refactoring_)
https://martinfowler.com/bliki/UnitTest.html[balanced and pragmatic tour]
of what unit tests are, and of the tradeoffs around speed.

A Take From the World of Functional Programming::
"Grokking Simplicity" by Eric Normand
explores the idea of "Functional Core, Imperative Shell".
Don't worry, you don't need a crazy FP language like Haskell or Clojure to understand it,
it's written in perfectly sensible JavaScript.
// CSANAD: Shouldn't we provide a link to this book too?
// https://www.oreilly.com/library/view/grokking-simplicity/9781617296208/
// O'Reilly resources usually have a different kind of link though.


Happy testing!
Loading