diff --git a/chapter_27_hot_lava.asciidoc b/chapter_27_hot_lava.asciidoc index a30fa004..d92f31a4 100644 --- a/chapter_27_hot_lava.asciidoc +++ b/chapter_27_hot_lava.asciidoc @@ -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! ______________________________________________________________ @@ -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, @@ -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. @@ -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:: @@ -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 <>. +as in <>. +// 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 @@ -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 @@ -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. @@ -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 @@ -422,6 +457,12 @@ call this approach "Ports and Adapters" (see <>). .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), @@ -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. @@ -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. @@ -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"))) @@ -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:: @@ -601,8 +645,8 @@ 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:: @@ -610,6 +654,9 @@ A Take From the World of Functional Programming:: 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!