TDD vs. BDD: Are You Using the Right Development Approach for Digital Transformation?
The debate over test-driven development and behavior-driven development has been breaking out in blog posts, hackathons, and enterprise IT departments since the mid-2000s. To this day, there are plenty of diehard proponents on both sides. Given the degree to which both business and software landscapes have evolved, the time is ripe to revisit the topic and ask: How do these development approaches contribute to the agile, software-centric, customer-obsessed state so many businesses in 2020 strive to achieve through digital transformation initiatives? Does one stand over the other in the new day-to-day business reality?
First, let’s address a small semantic issue that has tripped up many a novice. The use of continuous testing is not confined to TDD; both approaches make ample use of tests to ensure software functions properly throughout the production cycle. The fundamental differences between these two approaches lie in how the developer imagines the application he’s trying to develop and the route taken to bring it into reality. For example, a TDD approach looks first at the inside of the app — the desired individual features. The BDD approach, by contrast, looks outside the app — at the way the user will experience it — to determine the production roadmap.
The TDD developer thinks about the application as a product, which can be broken down into a set of features. He determines the bare minimum functionality a feature needs to have, then writes a test for the feature. This is the most critical part: he writes the test before he writes any code. Since neither the code nor the feature exists, the test naturally fails. With the failed test in hand to provide some guidance, he writes the smallest possible amount of code needed to produce a feature that can pass the test. If necessary, he’ll go back and refactor the code to remove any duplication and non-essential material. Once satisfied, he moves on to developing the next feature on the list. The cycle of writing a test for a feature, having it fail, writing code until you produce a feature that passes the test, then refactoring is known in TDD parlance as Red-Green-Refactor.
In BDD, the developer begins by imagining the application as more of an experience — something with which an end user interacts. He puts himself in the position of that user, conjuring various scenarios and outcomes, then thinks about what app specifications would be needed to achieve those outcomes. These scenarios are made into explicit user stories which plot out the user’s navigation of the application. User stories then become test cases, which basically ask the app to do certain things under certain conditions, and the code is written to meet those requirements.
You may be feeling just a tad confused at this point, asking: Doesn’t the TDD developer have to think about the behavior of the application at some point? And does the BDD developer not have to develop features just like the TDD developer? Good news: You’re right on track.
These approaches to development aren’t different the way cats and dogs are different. They’re different the way Cocker Spaniels and Beagles are different. They share basic DNA — naturally, TDD developers must think about the behavior of the app they’re building, just as BDD developers must test features continually to ensure proper functionality. The difference is the North Star of development — with TDD, it’s Red-Green-Refactor; with BDD, it’s desired end behavior. It should be noted that it is certainly possible for a developer to blend BDD and TDD in any number of ways in the development of a single app!
Although the difference is, to a considerable degree, in the heads of the development team, the path chosen can impact the practicality and cost of the project, communication within the company or with clients, and common DX goals, like moving IT closer to the business.
So, how do these two approaches stack up? Glad you asked.
TDD proponents argue that the Red-Green-Refactor process helps developers quickly build features with only necessary code and prevent over-engineering. For example, to build a messaging feature, developers would begin writing a test for the most minimal functionality they’d need, then write the code to fulfill that need, and keep adding until they have just enough to make a working feature. They also assert that putting testing at the forefront of each feature build provides them with usable tests right out of the gate that they can use to check the code in the future.
On the BDD side, some have countered that slavishly adhering to Red-Green-Refactor can result in feature-building that is overly technical –the concern being that developers may wind up testing and coding for granular details that don’t matter to the end user. They say that BDD’s exclusive emphasis on how a person will use the app in real life is a better use of development and testing time and resources. BDD can consolidate the technical code and tests as well as functional tests and features into a single “requirement” or “specification,” streamlining development and making it more efficient. BDD developers may choose to backfill some more granular tests to catch bugs after they achieve a design that passes user test cases.
Also, unlike TDD documentation — most of which only skilled programmers can really understand — BDD user stories and test cases are written in plain, human language.
This is their basic structure:
In the design of a real app, this may read:
Given: The user is logged in
When: The user clicks “Messages”
Then: The user is directed to the messaging inbox
These scenarios provide a handy reference for anyone involved in the project, be they developers, CIOs, business analysts, quality analysts, or others. In fact, this common language is practically indispensable for developers building software applications for off-site clients who may not comprehend pages of development jargon. Speaking in a way that everyone can understand ensures that there is little to no miscommunication about progress or what is being delivered.
At CMHWorks, we employ the BDD approach. Marc Jones — our Sr. QA Analyst — explains why we choose BDD:
“Behavior-driven user stories provide repeatable high-level tests for regression throughout the application. If QA/UAT ever run into a case where business users forget the functionality they’re asking for, this benefit will work really well for us.”
It should be obvious that anyone going the TDD route is going to get plenty of practice writing all kinds of tests. While automated testing with products like Cyprus.IO can help accelerate and streamline processes, there isn’t much getting around it: The amount of testing in TDD might take up as much as half of a developer’s time and, inevitably, the cost will be high.
While BDD is also largely test-driven, and developers will certainly test code before they write it, they don’t religiously test every particle the way TDD developers do. For example, they may run an end-to-end test for a certain application behavior rather than individual unit tests of each, potentially trivial, component. Testing just what is important in terms of the application’s behavior will usually require less time and is, therefore, the more frugal approach. One could also argue that end-to-end tests are often better than unit tests at gauging whether your app is doing what it should when in use.
TDD proponents typically stand firm in their argument that allowing upfront automated feature testing rather than user stories results in the most clean, minimal code. BDD developers rebut that coding only for specific desired behaviors will ensure nothing unnecessary makes it into the code. It is important to note, though, that BDD testing may require more in the way of heuristics or judgement calls than TDD does. Which approach results in better code will often depend on the individual developer and how well-adapted he or she is to one or the other.
Maintaining a functioning, bug-free application depends on proper testing. Some may argue that TDD has an edge here, since a team has all the tests they’ll ever need (until changes are committed) as soon as they’re done developing. Advocates of BDD, however, may argue that many of the recorded tests are not worth running again, since 100% code coverage is not necessary to ensure an app is working properly. In fact, many developers and quality analysts have said that 70% code coverage for testing is plenty. What’s more, modern technology has given us tools such as Cucumber JBehave and Specflow, which can actually generate automated tests from BDD’s human-readable given-when-then statements. Instruments like these are invaluable to CMHWorks, as we believe that the Product team (read: non-coders) should be responsible for defining what is needed and acceptable, from a requirements and test case definition standpoint.
Digital-Transformation (DX) Potential
Let’s start with why digital transformation is important. The basic goals of DX are: becoming more agile and iterative to cater to changing customer wants, making software a more central part of business, moving IT out of the backroom and into business discussions, and breaking down department silos.
In order to check these boxes, interdepartmental conversation is critical, but that dialogue is impossible in a world where developers speak one language (as in TDD tests and code) and business executives, product managers, marketers, and salespeople speak another. The BDD approach takes a highly technical process and turns it into plain English, folding once-foreign development teams and non-developer types into a single, cohesive unit.
Consequently, a Marketing representative can read through user test cases, spot a feature many customers complained about in a recent survey, and suggest a change to Development, who reworks that particular bit of code just before release. Voila! An agile organization, with IT and business working together to reach customer-centric goals.
Best Bet for All-Hands Agile
TDD and BDD are both great approaches to agile development. Developers who are accustomed to TDD and have no great need to communicate with laymen about development goals may have little reason to switch to BDD. On the other hand, companies trying to make software more central to their business need a means to democratize development. BDD’s plain-language user stories and test cases allow many heads — not just coders’ — to improve upon software releases.
This can provide a huge business advantage, as digital transformation is forcing companies to progressively leverage the strength of their digital interactions with customers. BDD fits so well into agile business schemas, which are core to many DX strategies, some have even said that your business isn’t agile if it’s not using BDD.
On the other hand, you could just teach your business people to code?