Test-Driven Development (or TDD) is an approach to coding where you write your tests first, then write the code that gets them to pass. For years, I've said that while I see the value of TDD, it doesn't align with how my brain works. Turns out, I was just doing it wrong! Today, we're going to look at TDD the right way. Let's dig in! This article is part of an ongoing series of JavaScript testing. In past articles, we looked at buildless testing, an overview of testing approaches, how to write unit tests, and how to organize tests. What is Test-Driven Development, exactly?With Test-Driven Development, or TDD, you write your tests first. Because you haven't written any code, the tests should fail. If they doesn't, the tests aren't actually testing anything useful. Then, you write code until you get all of the tests to pass. Once they do, you can go back and refactor the code to make it easier to read, maintain, and so on. Your tests should continue to pass, unless you messed something up. This process is often referred to in the TDD community as Red => Green => Refactor. The lightbulb momentOne of the biggest reasons I shunned TDD for so long—an argument I hear from many other people as well—is that I don't exactly know how much script is going to work until I write it and start exploring with code. How can I test something I don't know yet? Then I watched this amazing talk from Ian Cooper on TDD misconceptions, and a lightbulb went off. JavaScript tests shouldn't be testing how your code works. They should be testing what it does. Behaviors, not implementation details. For nearly a decade, I'd written tests that tested implementation details. Or more often, didn't write tests at all, because every time you change how your code works, the tests break. In TDD, that shouldn't happen! You only test the outputs and behaviors, not how the code gets there. As long as the output changes, you can refactor the underlying code as many times as you want without touching the test. Why is TDD good?Like many developers, my approach to testing over the years has mostly been code first, test last (or not at all). The idea with testing last is that you wait until you know exactly how your code is going to work, and get it working. Then you write some passing tests. In the future, if a refactor breaks the code, the tests will catch it. But generally, tests written this way break everytime you refactor, even if the code is still doing what it's supposed to, because it's tied to heavily to how the code works and not what it does. After playing around with it for a bit, here's where TDD really wins for me…
With that out of the way… Let's write some tests with TDD!We want to build a
Before we write any code, we're going to write some tests to define the behaviors we expect from our library methods. (If you've never done this before, go read my article on how to write unit tests first.) Inside my
Here's the behaviors I'd expect from this method…
And here's how I would express that as a set of tests…
If I run my test file at this point, nothing will show up, because the Writing our libraryInside my Then, I create an
Now my tests run, and everything is failing/red, just like we expect. Time to actually write some code! I'm going to add a rest parameter called Then, I'll loop through each
If we jump over to the testing suite, all of our tests are now passing! Catching unexpected errors with TDDThat one was pretty straightforward. But let's look at an example where TDD catches an error we might have missed (or that would have taken us longer to figure out) using other approaches. First, we'll add tests for the We can copy/paste the tests for the
And here's the updated tests.
Back in my Then, I return it back out.
If we jump back over and run our tests… the first two fail! The tests tell use that we're getting negative numbers when we expect positive ones to be returned. Fixing the errorsLooking at our code, I quickly realize that we're not subtracting subsequent numbers from the first. We're subtracting them from To fix that, I use the
Now, when we loop through our array, each number is subtracted from the first. If we run our tests again… the first two tests pass, but the last one fails! The tests tell use that we're getting undefined when we expected Looking at the code, I realize that if we pass in no numbers at all, the
I use the or operator ( Now, all of our tests pass. RefactorNow that all of my tests are passing, I can refactor my code to make it easier to read and maintain. I might add JSDoc comments to describe the parameters and what's returned. I might rename some variables, or use a ternary operator instead of the or operator in my The specifics—the implementation details—don't matter much. They'll vary from dev-to-dev and team-to-team. As long as the behavior of the library is the same, your tests will continue to pass, regardless of what you change under-the-hood. Moar testing?Now that this has finally clicked for me, I'm going to be writing tests a lot more. Hopefully you will, too! You can download the source code from today's article on GitHub. And if there's a topic you want to hear more about, send me an email and let me know! Cheers, Want to share this with others or read it later? View it in a browser. |
0 Komentar untuk "[Go Make Things] TDD for JavaScript with buildless Mocha and Chai"