Slide 1

Slide 1 text

doodlingdev

Slide 2

Slide 2 text

doodlingdev Your TDD Tr ea sur e Map

Slide 3

Slide 3 text

doodlingdev Aji they/them (all pr onoun s welcome) Hi! I mean.. ahoy! I'm Aji (hard J) I've been a professional developer since 2016, but if you count Geocities, I've been putting code on the web since 1996. Anyone in the room not yet born in 1996? I'm very excited you're here but now wish I had not asked that

Slide 4

Slide 4 text

doodlingdev introductions I never know what to say in these intros.. so how about.. when I was in 4th grade I got the lead in the school play

Slide 5

Slide 5 text

doodlingdev "Of Mice and Mozart" where we told the life story of Wolfgang Amadeus Mozart through the eyes of a family of mice that lived in his walls I played Mozart at 9 and I've been trying to relive that glory ever since

Slide 6

Slide 6 text

doodlingdev let's begin I'm going to take a guess that we're on the same page about something, I'm going

Slide 7

Slide 7 text

doodlingdev to assume that everyone here agrees that

Slide 8

Slide 8 text

doodlingdev testing is important. And

Slide 9

Slide 9 text

doodlingdev that Test Driven Development can be massively bene fi cial

Slide 10

Slide 10 text

doodlingdev You're here at a software conference of a

Slide 11

Slide 11 text

doodlingdev 🤓 community that overwhelmingly appreciates automated

Slide 12

Slide 12 text

doodlingdev 🤓🤓 testing and you came to listen to "Your TDD Treasure

Slide 13

Slide 13 text

doodlingdev 🤓🤓🤓 Map” which might just imply that TDD is a kind of treasure

Slide 14

Slide 14 text

doodlingdev the benefits of tests (briefly) So I'm going to skip the arguments that try and convince you of the bene fi ts of robust automated tests that

Slide 15

Slide 15 text

doodlingdev verify code verify your code is working properly

Slide 16

Slide 16 text

doodlingdev defend against regression defend against regressions

Slide 17

Slide 17 text

doodlingdev support refactoring support refactoring

Slide 18

Slide 18 text

doodlingdev living documentation act as living documentation

Slide 19

Slide 19 text

doodlingdev design guidance and provide design guidance.

Slide 20

Slide 20 text

doodlingdev ( From Five Factor Testing By Sarah Mei ) madeintandem.com/blog/five-factor-testing/ And although I didn't understand the degree at the time, that was certainly the feeling they tried to instill in us at my coding bootcamp

Slide 21

Slide 21 text

doodlingdev Please sir, I’d like some more tests.. but we had so little time, and I graduated never having written a test, without feeling the bene fi ts of a good test suite...

Slide 22

Slide 22 text

doodlingdev plus It seemed like a paradox. Write the thing that veri fi es the code I will have written BEFORE I am going to have written the code I will have been about to write.

Slide 23

Slide 23 text

doodlingdev PFFFT okay, let me just jump into my time machine to take a look at the PR I'm going to put up tomorrow.

Slide 24

Slide 24 text

doodlingdev Testing FIRST is di ff i cult. True for seasoned sailors, but even more so for those newer to this career when it's a challenge still to even reason about what code to write at all.

Slide 25

Slide 25 text

doodlingdev How was I going to make it out of this mess? Like Archimedes in the bathtub or Newton and Gravity, we need a compelling yet apocryphal story of discovery to go with it.

Slide 26

Slide 26 text

doodlingdev So.. scratching my head over this problem I wandered over to my bookshelf that has all my jobby job career type books.

Slide 27

Slide 27 text

doodlingdev It holds Sandy Metz's Practical Object Oriented Design in Ruby

Slide 28

Slide 28 text

doodlingdev and Atul Gawande's The Checklist Manifesto, wonderful tomes that have set me on the path when I needed them before...

Slide 29

Slide 29 text

doodlingdev wait.. this is Robert Lewis Stevenson's Treasure Island. what? How did this end up on this shelf? so embarassing, the child of a librarian, misshelving happening in my own home.. But it dawned on me, of course it's here! because...

Slide 30

Slide 30 text

doodlingdev treasure maps! Ok well..

Slide 31

Slide 31 text

doodlingdev fl owcharts

Slide 32

Slide 32 text

doodlingdev But think about it, a treasure map IS a fl owchart. Sure, one of the core stengths of a fl owchart is the branching, the logic, being able to map out decisions that lead to di ff erent outcomes but Stevenson's captain Flint only wants the happy path that ends in dubloons

Slide 33

Slide 33 text

doodlingdev if we fi ll out the map

Slide 34

Slide 34 text

doodlingdev put a decision branch here at the edge of this dense jungle

Slide 35

Slide 35 text

doodlingdev 🗺 ❓ without the map in our hands, we're lost and 404 not found

Slide 36

Slide 36 text

doodlingdev 🗺 ❓ one way lies treasure and the other to

Slide 37

Slide 37 text

doodlingdev 🗺 ❓ ⚔ an encampment of rival pirates and 409 con fl ict

Slide 38

Slide 38 text

doodlingdev 🗺 ❓ ⚔ a decision here

Slide 39

Slide 39 text

doodlingdev 🗺 ❓ 💰 ⚔ and EAST means treasure, but

Slide 40

Slide 40 text

doodlingdev 🗺 ❓ 💰 ⚔ 🐊 WEST means eaten by crocodiles, and just like that the whole crew is 410 gone

Slide 41

Slide 41 text

doodlingdev 🗺 ❓ 💰 ⚔ 🐊 Not only is a fl owchart useful for retracing your steps to your long-buried ill-begotten gains, but one of the most helpful artifacts for understanding the control fl ow of a system, invaluable documentation for new team members.

Slide 42

Slide 42 text

doodlingdev A kind of visual pseudocode.. Think about how many low-code and no-code solutions are built with fl owcharts as a UI, because they're so simple to understand but potentially powerful.

Slide 43

Slide 43 text

doodlingdev we can leverage that same strength as a shared language to build understanding between technical and non-technical team members and stakeholders and get buy-in from "the business" in a way you never can with code.

Slide 44

Slide 44 text

doodlingdev But no longer will the usefulness of this tool stop at the code's edge, we're going to learn how to directly apply it to writing tests and eventually code...

Slide 45

Slide 45 text

doodlingdev (pirate voice) So consider yerselves hornswaggled, ensnared inta' being my crew aboard the good ship Capybara, en route to the promised land where testin' before ye' leave harbor can be smooth saillin'. Before his half hour be over, we'll raid the ship o'knowledge and you'll have new techniques o' yer own te' boot

Slide 46

Slide 46 text

doodlingdev I apologize for that accent to everyone watching who is a 17th century Carribean pirate, sorry.. privateer

Slide 47

Slide 47 text

doodlingdev the process A chart can relate fairly directly to code, serving to mimic the control fl ow of an app.. but how it relates to testing might not be as obvious. We'll use a pretty common situation of a Rails controller action to demonstrate how we can take a handful of AC's to a fl owchart and turn that into a test rigging, test code, and application code.

Slide 48

Slide 48 text

doodlingdev couple of quick caveats and de fi nitions to simplify our coming parlay

Slide 49

Slide 49 text

doodlingdev feature when I say feature, i mean that to be any unit of work.. be it a whole feature, a bug fi x, partial implementation, whatever. I'll stick to saying "feature" for brevity.

Slide 50

Slide 50 text

doodlingdev rigging There's probably an actual term for it, but when I'm talking about a test suite's "rigging" i mean the describe, context and it blocks that make up the tests.

Slide 51

Slide 51 text

doodlingdev Rspec.describe PiratesController d o describe 'pirate/id' do context 'when logged in' d o it 'shows the pirate page' do like here, these lines with the descriptive strings, and the levels of indentation that show how they relate to one another, that's what I'm calling the "rigging"

Slide 52

Slide 52 text

doodlingdev rspec although this process will work with any testing library... ruby or not, my examples are going to be in rspec, because as we all know it IS a pirate's

Slide 53

Slide 53 text

doodlingdev arrrrr-spec favorite testing framework

Slide 54

Slide 54 text

doodlingdev The app our team is building is Pirate Cove, where freelance freebooters can list their available skills and raiding resume for captains looking to round out a crew for upcoming misdeeds.. sorry.. adventures

Slide 55

Slide 55 text

doodlingdev Pirates Users our app has users, we call them pirates, and pirates have pro fi le pages, o ff the shelf rails resource routing with the standard CRUD actions

Slide 56

Slide 56 text

doodlingdev Pirates piratecove.app/pirates/:id our app has users, we call them pirates, and pirates have pro fi le pages, o ff the shelf rails resource routing with the standard CRUD actions

Slide 57

Slide 57 text

doodlingdev Pirates Create, Read, Update, Destroy piratecove.app/pirates/:id our app has users, we call them pirates, and pirates have pro fi le pages, o ff the shelf rails resource routing with the standard CRUD actions

Slide 58

Slide 58 text

doodlingdev crew mob programming This afternoon we're pairing, all of us, I'll drive we've picked up a ticket with a new user story

Slide 59

Slide 59 text

doodlingdev As a pirate, I should be able to fill out the form on my profile page and submit it to change my information and it looks like it is to implement one of those CRUD actions, As a pirate, I should be able to fi ll out the form on my pro fi le page and submit it to change my information.

Slide 60

Slide 60 text

doodlingdev Acceptance Criteria (ACs): 1. User can update a pirate's information from the profile page (read slides) There are two eventual acceptance criteria or requirements on this ticket, but we're going to start with just the fi rst and pick up the second as we go.

Slide 61

Slide 61 text

doodlingdev Begin with the action we know is going to take place, typically a user acting on the system here: Our pirate user submitting form data.

Slide 62

Slide 62 text

doodlingdev Standard fl owchart symbols have start and end points as rounded shapes, We'll start with that core action at the top center of our workspace

Slide 63

Slide 63 text

doodlingdev User submits form data when that gets submitted, an action occurs on the backend, we're going to save that new data

Slide 64

Slide 64 text

doodlingdev User submits form data DB Save and how do we resolve? show the updated information with a redirect to :show

Slide 65

Slide 65 text

doodlingdev User submits form data DB Save Display profile this alone could be the happy path of our feature sure it's gonna get a little more complex but at least it's enough to write the matching rigging

Slide 66

Slide 66 text

doodlingdev User submits form data DB Save Display profile Begins with a user action, some backend work, and feedback for the user. Beginning middle end

Slide 67

Slide 67 text

doodlingdev User submits form data DB Save Display profile # frozen_string_literal: true RSpec.describe PiratesController, type: :request do describe “patch#update” do (pause) at the top of an rspec fi le we get something like this to start, but everything we're doing will be under patch#update, this is the last time we'll see this to save the slides getting too cluttered

Slide 68

Slide 68 text

doodlingdev User submits form data DB Save Display profile right away I can see two outcomes that we expect will happen after form data is submitted.

Slide 69

Slide 69 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” by rails convention: redirecting to the pirate show page and the only way the pirate show page is going to have the proper information

Slide 70

Slide 70 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” is if we also update the db to re fl ect changed data

Slide 71

Slide 71 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” This doesn't mean that every bubble in the fl owchart needs to be tested, and we'll see that coming up. In this case, we're testing more than just the very end, but also any action that changes something *outside* of our current test subject. A side e ff ect.

Slide 72

Slide 72 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Our test subject is the PiratesController, and this makes a change in the database, way outside the controller. That's a result that we want to guarantee is happening (to the best of our ability) so we'll protect it with a test.

Slide 73

Slide 73 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” That way, if anyone ever comes along and makes a change that a ff ects that outcome

Slide 74

Slide 74 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” ⁉ even if the redirect still happens

Slide 75

Slide 75 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” 💬 thank you. we'll have feedback that an expected result has been a ff ected. That's our tests preventing regressions.

Slide 76

Slide 76 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” (pause) The other piece to our test rigging are context blocks. The it blocks are going to match up to the END results, the e ff ects of the action

Slide 77

Slide 77 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” the context will correlate to the setups that exist, those are found by following each individual path through the chart

Slide 78

Slide 78 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” pretty easy at the moment, right now we've only got one path through the fl owchart

Slide 79

Slide 79 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” it could make sense to wrap these two it blocks in a context block

Slide 80

Slide 80 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” context “happy path” do end but i don't think we actually gain anything by doing that, it's the only context that exists, and it's already wrapped by the "patch update" describe block. Personal preference, but I'd leave it o ff for now.

Slide 81

Slide 81 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” context “happy path” do end What else this indicates by being only one context, is that our setup for these two tests will be the same.

Slide 82

Slide 82 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” 👋 Each individual path through the chart will have a di ff erent state when the action is performed. We're focused down to a level where there is only one action, and most of the time you’re building out tests, that's

Slide 83

Slide 83 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” how it’s going to be. Maybe di ff erent granularities, sometimes di ff erent params, but one single insighting action.

Slide 84

Slide 84 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” The only way to take different paths through the chart is with a different beginning state or different params of the action In the ideal state when you’re focued on testing one action, the only way to take di ff erent paths through the chart is with a di ff erent beginning state, or di ff erent params of the action.

Slide 85

Slide 85 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” so we're still here, we kinda know that it's not going to stay this simple And this is a position you might fi nd yourself in often. You know there's more looming, but it hasn't actually shown up yet.

Slide 86

Slide 86 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” let's not complicate it, I'd rather start moving forward on something I'm sure of, naive or not, rather than speculate and end up down an irrelevant rabbit hole.

Slide 87

Slide 87 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” We've got some ambiguity, but we've also got something concrete, so let's move forward on that, I'm con fi dent enough that what comes next will reveal itself as we go through this exersize or that if it doesn't...

Slide 88

Slide 88 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” it could be outside the scope of what we're trying to accomplish right now, plus I want to err on the side of shipping software over analysis paralysis

Slide 89

Slide 89 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” and really, this is the whole happy path, right? nothing goes wrong, this is essentially what needs to happen.

Slide 90

Slide 90 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” So if we write these tests, we'll have a north star to guide us as we sail along and seas get choppier. If ever we make changes, and THESE tests fail, we should do some rethinking.

Slide 91

Slide 91 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Yup, our new tests will be preventing OUR regressions. Just another reminder that "the next developer" who will work with code we've written... can be ourselves, even just an hour later.

Slide 92

Slide 92 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” So, should we write some tests?

Slide 93

Slide 93 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” given when then the action the setup the result Wait, before that, I'm also not here to introduce or debate the di ff erent methodologies for writing individual tests, that's another talk, or workshop. And they mostly all boil down to some variation of GIVEN, WHEN, THEN.

Slide 94

Slide 94 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” it “redirects to pirate :show” do end what might test code for this portion of our rigging look like?

Slide 95

Slide 95 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end let's start with the setup, we know we need a pirate whose information is going to be updated, and whose ID will be part of the url, based on rails' restful conventions.

Slide 96

Slide 96 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end and now the action, we already said, that's going to be when the user submits the form data, so if we use rspec's request syntax, it might look something like this

Slide 97

Slide 97 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) and eventually our expectation, that it should redirect

Slide 98

Slide 98 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end Here we are with test code for both it blocks from before. Redirects to the user show page and updates the database.

Slide 99

Slide 99 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end Now we’ve got some wind in our sails! We’ve understood our fl owchart as a context and still at just the one path, our GIVEN is the matching setup. (Pause)

Slide 100

Slide 100 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end the action that begins our fl owchart has become the WHEN: the action taken in our test cases.

Slide 101

Slide 101 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end We’ve identi fi ed the two end states, one for the http response, and one for the database

Slide 102

Slide 102 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end And we’ve captured them as our THEN in expectations

Slide 103

Slide 103 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end (pause) As I'm building out a system, I'm trying to uncover moments where we might be taking something for granted. An assumption that we've built on top of that isn't as guaranteed as we're treating it

Slide 104

Slide 104 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end So I'm asking myself, 'what here is _built on a lie_?' what here could go wrong? and my eye is drawn to this.

Slide 105

Slide 105 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end These params are sent in by a user. You know users, and so do I...and I don't trust 'em. They will fi nd ..interesting ways to stress a system. Brand new ways to use our software that we never dreeeeamed of.

Slide 106

Slide 106 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) it “redirects to pirate :show” do end expect do patch(pirate_url(test_pirate), params: { name: “Captain J. Flint”, position: “Captain” }) end .to redirect_to(pirate_url(pirate)) it “updates db to reflect changed data” do test_pirate = Pirate.create({ name: "Billy Bones", position: "First Mate" }) patch(pirate_path(test_pirate), params: { name: “William Bones”, position: “Captain” }) expect(Pirate.find(test_pirate.id).name) .to eq "William Bones" end In reality, that's a gift, it really is and I believe that. But right now.. it's a problem. So far our tests are assuming everything is going to go smoothly. We need to handle what happens when patch params don't pass validation.

Slide 107

Slide 107 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Let's fold up the test code, like we're in our editor, and add this params protection. What would params that don't pass validation change about the fl ow of the chart?

Slide 108

Slide 108 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Yesss! That change will never make it to the database. And because that can fail, we need to add to the fl owchart, before the persistence, a check for validity.

Slide 109

Slide 109 text

doodlingdev User submits form data it “redirects to pirate :show” it “updates the db with changed data” Valid? DB Save Display profile We notate this fork in the road with a diamond Because in Flowchartland, which is a province of Diagramopolous, a diamond represents a decision. Something in the setup or the action is a ff ecting the outcome

Slide 110

Slide 110 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no the value of which decides the branch of the fl ow to continue down, and now we truly have more than one path through the feature, and with it another context that needs testing.

Slide 111

Slide 111 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no let's trace the two paths so we can see what we're dealing with

Slide 112

Slide 112 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no if a path is a context, we're able to tell that one context is separate from the other. the nodes in the fl owchart that are re fl ected in the rigging as our ...

Slide 113

Slide 113 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no in the rigging as our ...existing specs cannot be reached by the new path, they are an entirely di ff erent context

Slide 114

Slide 114 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no let's re fl ect that in the rigging. (pause) But how can we know what the context involves, it's not as simple as an endpoint.. there isn't one node in the fl owchart that equates to context, but many along a path.

Slide 115

Slide 115 text

doodlingdev it “redirects to pirate :show” it “updates the db with changed data” User submits form data DB Save Display profile Valid? Show form with errors yes no Let's ask ourselves a question, what given, what setup or input will cause the decision to go to the right where we see the two it blocks we already have?

Slide 116

Slide 116 text

doodlingdev it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end User submits form data DB Save Display profile Valid? Show form with errors yes no valid params, right?

Slide 117

Slide 117 text

doodlingdev it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end User submits form data DB Save Display profile Valid? Show form with errors yes no and then the opposite, invalid params, causes the fl ow to the left.

Slide 118

Slide 118 text

doodlingdev it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" User submits form data DB Save Display profile Valid? Show form with errors yes no and the it block, based on rails conventions we'll render the edit page again and send the object over to the view with those validation errors attached

Slide 119

Slide 119 text

doodlingdev it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" User submits form data DB Save Display profile Valid? Show form with errors yes no Let's act on these tests and fl owchart that we have currently. what do we want to do next? Personally.. I'm not going to feel good about these tests unless I see them fail. We haven't written any code for them yet, so if they pass, there is something fi shy going on.

Slide 120

Slide 120 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" Finished in 0.0819 seconds (files took 5.08 seconds to load) 3 examples, 3 failures Great news! the tests failed. That means we can write some code to make them pass.

Slide 121

Slide 121 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" def update end We're going to keep this as simple as possible, but let's think about the code that we'll need in order to follow the fl owchart and satisfy the tests.

Slide 122

Slide 122 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" def update end @pirate = Pirate.find(params[:id]) we'll need to know which pirate

Slide 123

Slide 123 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" def update end @pirate = Pirate.find(params[:id]) if @pirate.update(pirate_params) redirect_to pirate_url(@pirate) if the update works, we'll redirect

Slide 124

Slide 124 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" def update end @pirate = Pirate.find(params[:id]) if @pirate.update(pirate_params) redirect_to pirate_url(@pirate) else render :edit end and if not, render edit. I didn't do anything fancy here, this is direct from the rails generators, condensed for slide readability. how do our tests fare?

Slide 125

Slide 125 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no it “redirects to pirate :show” it “updates the db with changed data” context "with valid params" do end context "with invalid params" do end it "renders :edit" Finished in 0.1219 seconds (files took 5.08 seconds to load) 3 examples, 0 failures bingo! great work every body.

Slide 126

Slide 126 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" Let's take just a moment to re fl ect on how we got here, we used the ticket requirements to make a simple fl owchart that met the user story, the happy path

Slide 127

Slide 127 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" and from that fl owchart came our test rigging

Slide 128

Slide 128 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" We wrote some tests and uncovered a failure state

Slide 129

Slide 129 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" which led us to expand on our fl owchart

Slide 130

Slide 130 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" and rigging

Slide 131

Slide 131 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" From there we used our understanding of the system at play to write the application code

Slide 132

Slide 132 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" chart , rigging , test , chart , rigging , code

Slide 133

Slide 133 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" All that is to say, this process isn't going to be linear most of the time.

Slide 134

Slide 134 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" Usually we won't have written the whole entire fl owchart with everything in scope, then move on to the entire rigging, then the test code, then the app code.

Slide 135

Slide 135 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" We'll bounce around, acting on the next bit of information that we're con fi dent about, uncovering assumptions as we go, and adding to our framework as we progress.

Slide 136

Slide 136 text

doodlingdev User submits form data DB Save Display profile it “redirects to pirate :show” it “updates the db with changed data” Valid? Show form with errors yes no context "with valid params" do end context "with invalid params" do end it "renders :edit" well.. we don't really have everything that's in scope, do we? remember, there's that second acceptance criteria.

Slide 137

Slide 137 text

doodlingdev Acceptance Criteria: 1. Can update a pirate's profile info 2. Only authorized pirates can perform updates 1 we already have, can update a pirate's pro fi le info, but 2 here says that only authorized pirates can perform updates.

Slide 138

Slide 138 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end so before our check for validity, in the same way that we added the valid? step before persistence

Slide 139

Slide 139 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end we have a new step that can interrupt the process before reaching the end states we had charted before

Slide 140

Slide 140 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end which leads to another path through the chart. ignore for now the implementation of even having a logged in user, I've only got ( x ) more minutes with you.

Slide 141

Slide 141 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end another path should make us think what? another context

Slide 142

Slide 142 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end using the technique we did before, we can wrap the expectations based on when their paths diverge. The fi rst time any paths diverge, they go in two di ff erent directions. Green to the left, blue and orange to the right.

Slide 143

Slide 143 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end That tells us there will be two contexts, and it's the decision where they branch that tells us what the context is.

Slide 144

Slide 144 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end Authorized, no: that's green.

Slide 145

Slide 145 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end and because the other paths share the state of a pirate that has permissions to change this data

Slide 146

Slide 146 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end the context about being authorized will wrap them both.

Slide 147

Slide 147 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end But we've done this kind of exercise before.. why bring it up again? because I want to throw a metaphorical match in our powder keg.

Slide 148

Slide 148 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end Turns out what makes someone authorized... isn't so cut and dry. Authorized yes/no is perfectly fi ne for the fl owchart here... because at the controller level, that's the fl ow of this action.

Slide 149

Slide 149 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end but to be authorized.. the logged in pirate is EITHER the pirate being changed OR a pirate with the admin role

Slide 150

Slide 150 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end Same Pirate? no yes no yes Admin? what was once 3 paths through the chart is now fi ve, if we re fl ect that in the test cases we go from 4

Slide 151

Slide 151 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no 401 Same Pirate? no yes no yes Admin? context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end to 7. that's 57% more tests.. and I like tests and all, but conceptually this doesn't feel too much di ff erent than what we already had

Slide 152

Slide 152 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no 401 Same Pirate? no yes no yes Admin? context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end We added this section, but it makes the same decision: authorized yes or no.. it's just a more complicated process. Maybe you're already standin' where i'm leading you.. or maybe you're on the way..

Slide 153

Slide 153 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no 401 context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end Same Pirate? Admin? no yes no yes if this box was opaque...

Slide 154

Slide 154 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no 401 Same Pirate? no yes no yes Admin? context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end Authorized? and all we saw was authorized yes/no.. the rest of the paths would have the same information and the same fl ow, right?

Slide 155

Slide 155 text

doodlingdev context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end User submits form data DB Save Display profile Valid? Show form with errors yes no 401 Same Pirate? no yes no yes Admin? Authorized? Does the PiratesController need to know how to tell if a pirate can make the change? or does it just need to know whether to make 'em walk the plank or not? the latter, right?

Slide 156

Slide 156 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no 401 context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end Same Pirate? Same Pirate? no yes no yes Authorized? Call with pirate and editing pirate Same Pirate? Admin? no yes no yes Unauthorized Authorized so let's encapsulate that logic in an object. Lookit this, robert lewis stevenson and standy metz, back together after all this time.

Slide 157

Slide 157 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no 401 context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end Same Pirate? Same Pirate? no yes no yes Authorized? Call with pirate and editing pirate Same Pirate? Admin? no yes no yes Unauthorized Authorized and because we can test the authorization logic over in this object's tests... (some might even call it a service object) it doesn't have to be a part of our controller test at all.

Slide 158

Slide 158 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 User submits form data DB Save Display profile Valid? Show form with errors yes no 401 context "logged in user is the same user" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user is admin" do context “with valid params” do it “redirects to user show page” it “updates the db to reflect changed data” end context “with invalid params” do it “sends error message” end end context "logged in user not admin or user" do it “sends 401” end Same Pirate? Same Pirate? no yes no yes Authorized? Call with pirate and editing pirate Same Pirate? Admin? no yes no yes Unauthorized Authorized We can mock the call to the service object, within the test.. force it to say yes or no.. all part of our setup and suddenly we're back!

Slide 159

Slide 159 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end with just authorized yes/no. And the next time you're looking to encapsulate some logic away in a service object...

Slide 160

Slide 160 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end look for parts of your fl owchart where those paths go apart, do something self contained, but then converge back together. like we did here.

Slide 161

Slide 161 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end but if we think about it, we already have similar nodes in this fl owchart, don't we?

Slide 162

Slide 162 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end yes! right here! this isn't a single thing.. it's active record taking our params hash, doing --something-- with Arel, spitting out SQL, traversing to a database (a whole di ff erent program), updating a resource.. imagine the fl owchart on that!

Slide 163

Slide 163 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end and Active Record just handles it all so we can put a single box in our fl owchart.

Slide 164

Slide 164 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end In the same way that we zoomed IN to get to an authorization service class, and we understand the zooming behind the persist node, we can also zoom out from our controller.

Slide 165

Slide 165 text

doodlingdev User submits form data DB Save Display profile Valid? Show form with errors yes no Authorized? yes no 401 context "with valid params" do it "redirects to pirate :show" it "updates the db with changed data" end context "with invalid params" do it "renders :edit" end context "pirate is unauthorized" do it "returns 401: Unauthorized" end context "pirate is authorized" do end Up until this point we've been looking at a single action...and everything else happens without our in fl uence.

Slide 166

Slide 166 text

doodlingdev this is a fl owchart for ordering a book from amazon. this is very high level. really zoomed out, all the way to the user. evvvverything is abstracted away, they're not thinking about html, servers, databases, none of it. and yet this is an incredibly useful diagram, even for testing, even for writing code

Slide 167

Slide 167 text

doodlingdev in the same way that our happy path tests were our north star while building and refactoring, something like this can be the north star for an entire business or development team, able to ask themselves "can a user still order a book?" or "does this help a user order a book?". probably not amazon anymore because nowhere on here do I see "shoot founder into space". I don't see "let him come back" either but we did.

Slide 168

Slide 168 text

doodlingdev each of these purple blocks is an action by a user. sign in.. add to cart.. each and every one of them could be a controller action, each with it's own fl owchart as intricate (or moreso) than the one we just built. but at this level, this "can a user order a book" level, those aren't important, for the same reason that it wasn't important to our controller if the user was an admin or a speci fi c pirate.

Slide 169

Slide 169 text

doodlingdev still each branch or each fl ow is going to need a test, maybe at this level a context maybe not, again.. personal preference. but i see at least..5? 6? tests here? eventually every purple box reached by the path of a test from "start" to "end"

Slide 170

Slide 170 text

doodlingdev i hope that helps you see that these aren't "rules" on how to do the Treasure Map "technique", but some ideas and advice on how you might be able to apply it in your work. I literally do this in my work.

Slide 171

Slide 171 text

doodlingdev This is a commit message I wrote just last week. That's right.. I put the fl owchart IN TO The commit message. And if you too want your commit messages to bring all the boys to the yard

Slide 172

Slide 172 text

doodlingdev the tool I used to make this plaintext fl owchart is ascii fl ow at ascii fl ow.com. So yeah, take these ideas, use 'em, throw away what isn't working, add on where it falls short.

Slide 173

Slide 173 text

doodlingdev OH and if you DO add on or do something cool with it, please please tell me, on the twits, the gram, github, any of the things.

Slide 174

Slide 174 text

doodlingdev I would love to know how you remix this... or adapt it to other frameworks and languages because

Slide 175

Slide 175 text

doodlingdev Arr, We might be here under the auspices of land lubbin' RAILS rather than ocean waves, I can without OBJECTIVE-C whether yer features be crafted o' RUBY, EMERALD, carved of ELM, adorned with JADE and PERL or crusted in RUST, arrrrrrrR, this ELIXIR fl ies truthy as a DART for all who sail the C from JAVA to CEYLON. In LUA more formal errrrr..LANG-uage, and you might consider it BASIC, but even through a COMMON LISP I wont be hearin' any SMALLTALK, be'cuz this ship be SWIFT as an OCAML crossing the mighty GO ...bi desert. But to give this here GROOVY ASSEMBLY some UNITY and CLOJURE, let me be CRYSTAL clear with ye, ALGOL to Davy Jones' Locker and BASH a hundred foot PYTHON before I give up me Test Driven Development. And now that you've seen the AMPL SCAL-A this technique, I hope yer acceptance criteria ever be clear, yer test suite not scuttle yer deployment, and the cloud never take the wind out of yer sails, so that the good ship CAPYBARA can see you home.

Slide 176

Slide 176 text

doodlingdev madeintandem.com/blog/five-factor-testing/ "Five Factor Testing" - Sarah Mei asciiflow asciiflow.com