In week 3 Intro to Programming, we learned about Behavior-Driven Development. Behavior-Driven Development is the practice of breaking down a program into each of the smaller behaviors that create it. We then use these behaviors to drive the course of development. We begin addressing the simplest behavior, implement just enough code to get it functioning, confirm it works, and begin addressing the next simplest behavior.
In this lesson we'll review the benefits of Behavior-Driven Development. In the next lesson, we'll walk through the exact workflow of using Behavior-Driven Development in conjunction with automated tests. Finally, we'll learn how to install and utilize automated testing tools into our applications.
If you did not take Epicodus' Intro to Programming course, or if you'd simply like to refresh your memory check out the following lessons:
Behavior-Driven Development assists in tackling complex problems. If you were told to build a Pig Latin Translator you may not immediately know where to begin. You might start by writing one function, realize you need something else in place before this function can work, and your approach quickly becomes disorganized.
You likely already created a Pig Latin translator in Intro to Programming, so perhaps this challenge doesn't seem so difficult now. That's great! But what about an even larger program. How would you begin re-creating Facebook? Or the code behind a self-driving car?
It'd be difficult to even determine where to begin, right?!
Let's consider a brief example. Imagine you're training to become a chef. As a chef, you've been tasked to bake a lemon meringue pie.
Let's also assume you've never actually made lemon meringue pie! Perhaps you've seen one, eaten one, or have a general idea what it looks like, but you've never done it yourself. If you wanted to learn the most about baking lemon meringue pie, and create the best product in a reasonable amount of time, which of the following recipes would be the most helpful?
Bake a lemon meringue pie. It should have a crust, lemon filling, and a meringue topping.
* Preheat oven to 350 degrees. * Whisk together 1 cup sugar, 2 tablespoons flour, and 1/4 teaspoon salt in a saucepan. Stir in 1 1/2 cups water, and the juice of two lemons. * Cook over medium-high heat until mixture boils. Stir in 2 tablespoons butter. * Place 4 egg yolks in a small bowl and gradually whisk in the hot sugar mixture. Pour this filling into pie crust. * In a large bowl, whip 4 egg whites until foamy. Add 6 tablespoons sugar. Continue whipping until stiff peaks form. * Spread this meringue mixture over pie filling. * Bake in preheated oven for 10 minutes, or until meringue is golden brown.
No contest, right? The second recipe is absolutely superior. Not only does it lay out what you'll need to complete the task, but it details step-by-step instructions.
We can even consider just the first step in each recipe. Which one of these individual tasks is clearer and easier to accomplish?
Bake a lemon meringue pie. It should have a lemon filling, and a meringue topping.
Preheat oven to 350 degrees.
As you can see, by breaking down difficult, complex, or foreign tasks into small behaviors we can get much further, in much quicker time. And by focusing on each behavior individually, we often learn more too!
Now, consider a coding project. Let's once again imagine you must create a Pig Latin translator. Similar to the pie example, we'll pretend you've never coded one. You have an idea of what this program should do...but how do you get there?!
Take a peek at the following two "recipes". Which one would be the most helpful? Which one would help finish the project faster? Which organizes the workflow better, and likely results in a better end product?
* Build a Pig Latin translator. It should take any English word, sentence, or paragraph and return its Pig Latin translation.
* First, make sure it doesn't do anything to numbers or symbols, since those don't need translating. * For example: "4%" should still come out as "4%". * Next, make sure it can translate really basic, single-character words beginning with a vowel. * For example: "I" should come out as "Iay". * Once that's working, move onto multiple-character words beginning with a vowel. * "oats" should come out as "oatsay" * Then, work on translating single words beginning with consonants. * "cat" should turn into "atcay". * When you have that, move onto full sentences. * "I am a boat" should become "Iay amay aay oatbay"
Again, this is no contest. The second clearly outlines where to start, and what each step along the way looks like. Using this "recipe" would make the process of developing a Pig Latin application far quicker, easier, and better organized.
As you can see, there are countless benefits to using the Behavior-Driven Development process. Let's review:
By taking time to think through a program, identify behaviors, and tackle the simplest first, you're creating a gameplan. You're laying out each step you'll need to take in detail, like the superior Recipe Two above.
As cliche as it may sound; climbing a huge mountain is daunting. But taking a single step isn't. Even the most experienced coders can struggle with approaching complex issues. By starting small and working our way up we can make a seemingly-daunting task much more approachable. And we can get moving much quicker! As you begin coding small behaviors the larger picture will likely come into focus.
When we implement and test a single behavior at a time we're preventing errors. Testing each behavior before moving on allows us to spot bugs the moment they're introduced.
If we didn't use BDD, we probably wouldn't spot bugs until they actually broke our application. An if we added more code after the bug was introduced, other behaviors would likely rely on the buggy code! To resolve this issue we'd need to comb through everything, locate the bug, resolve it, and also alter all code that depended on the buggy code. That's a lot of work!
Starting a complex project can be daunting. Even if you aren't sure how to code the more difficult features of your application, you can get moving by implementing smaller, identifiable behaviors. As you work, the bigger picture will come into focus.
By testing behaviors as they're implemented, and ensuring previous tests still pass when new behaviors are introduced, new features are always built on a foundation of reliable, tested code.
By implementing the least amount of code to pass each test, you're keeping code DRY. By approaching each behavior individually you're also writing more modular code. Modular code is easier to maintain, update, and debug.
If you're here, you're interested in working in the tech industry. Testing is something you'll likely be expected to do at future internships and jobs, whether as a developer, a QA tester or a devops specialist. By developing good BDD habits you're gaining skillsets employers value. You'll also begin building a portfolio that contains many demonstrations of these skillsets.
In Intro to Programming, we "tested" each behavior by inserting sample input into our program and double-checking we received the correct output.
However, as our programs grow in complexity, manually testing an ever-growing list of specs will take more and more time. And it's not the way professionals test their code, either!
This week, we'll level up our BDD skills by writing automated tests for each behavior. While writing coded tests may take longer at first, you'll be able to test every single one of your programs' behaviors with a single command. And it only takes seconds!