2025 Public Training Schedule
January 14 – 17, 2025 – Agile Analysis and Design Patterns – Half-Day Sessions
(c) 2024 To Be Agile
Another huge benefit of Acceptance Test-Driven Development or ATDD is that it helps us flesh out edge cases, exceptions, and alternate paths for a story to follow. I far prefer to specify edge cases and exceptional paths through acceptance tests rather than with use cases because acceptance tests are more articulate and they are executable.
Acceptance tests also give me a way to call out edge cases upfront so we know to be aware of them. I simply write an acceptance test for each edge case or exception I think of and that helps me keep track of it as I build it out in the system.
Actually, I find that acceptance test-driven development is a great way of driving my to-do list because I can clearly see what features need to be done and what features are already complete.
Stories generally take the happy path. For example, if my story is about withdrawing funds from a bank account then I might have a story that says something like, “As a customer using the ATM, I want to withdraw one hundred dollars from my savings account so that I have the cash.” But what happens if there is less than $100 in the account? The story doesn’t cover that. It isn’t meant to. A story is a high-level conception of a feature in a system and therefore it doesn’t go into a lot of details.
For me, a story is exactly what Alistair Cockburn says, “a promise for a conversation.” A story is simply a one-sentence description of what a feature is, why it is wanted, and who it’s for. That’s not enough to code the feature up. We get the details we need to code by having a conversation with our Product Owner and fleshing out examples that lead us to write the correct set of acceptance tests.
My stories don’t have exceptional paths or error conditions in them typically but my acceptance tests do. It may not have all of the edge cases I end up implementing but it will typically have the major ones.
Now we get into a bit of a gray area because, as I said before, the real difference between acceptance test-driven development and test-driven development is a matter of the level of granularity we are working in. Acceptance test-driven development is about fulfilling acceptance criteria whereas test-driven development is about fulfilling the itty-bitty tiny steps involved in order to fulfill the acceptance criteria.
I have seen this work in different ways. Some teams like to call out a lot of edge cases in their acceptance tests and that ripples down into their code. Other teams simply think about the happy path in their acceptance tests and then they implement the edge cases and exceptions through writing unit tests. I have seen it work both ways.
And just like we specify our happy path we can also specify unhappy paths or exceptional conditions. In both cases, we typically use the “given, when, then” syntax. Given some set of preconditions, when a trigger occurs, then some set of post-conditions will occur.
For example, given Michael’s account has $99 in it, when Michael tries to withdraw $100, then the account should reject the request and generate an “insufficient funds” exception.
Notice how using the “given, when, then” syntax, we are immediately able to describe an example of the behavior that we want to create without specifying how to create that behavior? And this is yet another benefit of acceptance test-driven development.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software.
Previous Post: « Automate Acceptance Criteria
Next Post: Use Examples »