- Introduction
- Part 1: Why use it?
- Part 2: Write My Tests First?
- Part 3: Keys to Effective TDD
- Part 3, Key #1: Write Testable Code
- Part 3, Key #2: Write Good Tests
- Part 3, Key #3: Using Fakes and Dependency Injection
- Part 4: Conclusion
When I first read about TDD (many years ago), one of the first things I saw was: write your tests first.
“What?
This is stupid, I’m gonna go get a sandwich.”
That idea didn’t make sense to me, and I think that’s probably the reaction most developers who don’t use TDD would have.
How can you test something that doesn’t exist? Well, you can’t. But the idea, as mentioned in the previous post, is that this isn’t just about testing. It’s really about design.
“Ok, so I write all my tests and then write my code? How am I supposed to do that. I still don’t get it.”
That was a big misunderstanding of mine. You don’t write all of your tests up front, you write them one at a time and then write the code to satisfy those tests – one at a time. You start small and your tests force you to slowly create your classes and functions. Eventually, where there was a blank screen, now you have a bunch of functional code that is covered by tests.
The Red, Green, Refactor Show
The “test-first” approach basically has 3 steps:
- Red – Write a test and make sure it fails. It’s called the “Red” step because most unit testing tools will display a red failure message. Failure is good at this point. We love failure.
- Green – Write the minimum amount of code to make your test pass. And yes, the unit testing tools will display a nice lovely green message. Ah, green…success, peacefulness.
- Refactor – You have some code that passes a test, way to go. But guess what? That code sucks. Refactor that code so it is nice and pretty. This step doesn’t have to occur after each test is written. You might want to wait until you have a few methods, maybe even an entire module, done before you refactor it.
Where Do I Start?
Let’s see this in action with an example. Let’s say the first thing we want to do is write this “calculate shipping module”. We don’t know if it will be 1 method, or 10, or 100. But the tests will guide us.
All right, what’s the first requirement?
- Shipping = Order quantity * 3
What do we know? Well from that requirement I’d say we need a method that accepts order quantity as a parameter and returns that number multiplied by 3. Pretty easy, so let’s write our first test!
So with these 3 small lines of code, we are essentially creating the following truths:
- We have a class called ShippingCalculator.
- This class has a method Calculate(), that accepts an integer parameter.
- The Calculate() method will return the input parameter multiplied by 3.
Now that’s pretty cool! Of course, these aren’t exactly truths yet since this code won’t even compile (as evidenced by the red squiggly line!) But that’s the way we want it, we are in the red portion of red/green/refactor. And the first “red” test is the compile failure. So, let’s write enough code to make it compile:
There, now it compiles. However this is obviously not going to pass since we are actually throwing an exception in our method. But again, or goal here is to execute a test that fails first. Then we’ll make our method work. Just to be sure…
Yep, it fails – good. Now let’s write the minimum amount of code to make it pass:
And re-run our test:
Awesome! Now we have a class that satisfies our first requirement. We can move onto the next requirements by writing more tests and then implementing the code to make them pass. Eventually we’ll get to a point where we’re ready to refactor this code, which is the final part of red/green/refactor.
At that point, our Calculate() method will be completely covered by tests so we can refactor without fear! We know that if we break anything by accident (who me?) the test will slap us upside the head.
0 comments:
Post a Comment