Tales Of TDD - Stressed And Always In A HurryAugust 19, 2020
So I noticed that you completed that feature that we’ve been pair programming yesterday?
Yes, I was a little bored yesterday evening. So I decided to continue working on it
Thanks. I’m glad the feature is ready to go.
Definitely! I still have one question though. I’ve noticed that you added fifty lines of code to that controller method without adding any tests. What I also noticed is that you’ve added that new mapper class, but there aren’t any tests for that either.
Uhm, yes, uhm … about that …
Did you forget to check in the source files of the tests?
Well, in a sense that’s true. Because I didn’t write any tests.
I know that we’ve been using a test-first approach to build up this feature. I just wanted to finish up the implementation for this user story. I knew what the remaining code had to do, so I just wrote it. Sure, it required some more lines than I initially anticipated, but hey, it’s finished now. We can move on to the next user story. So I already …
Can I ask you another question?
Why are you in such a hurry?
I’m not in a hurry!
Well, to me it seems that you’re a bit pressed for time.
I just wanted to move on to the next user story.
Can we talk some more about the user story that we’ve been working on yesterday?
You’ve added some code yesterday evening. How do you know that this code actually works?
It works properly because I tested it.
Great! How did you exercise the code that you’ve added?
By running the application and clicking around in the UI.
You’ve added some code that builds a URL, right?
Did you execute the code inside this if-statement?
I don’t know. How can I be sure of that?
Well, you could have used some code coverage tool while running the application.
That sounds complicated.
Or you could have added a breakpoint for every execution path. There are four if-statements, so you need five breakpoints. One for each if-statement and an additional one in case all four conditions evaluate to false. Then you can start the application in debug-mode and go through the UI until you’ve hit all five breakpoints.
Well, that sounds like a lot of work. Debugging the application usually takes a lot of time.
You’re right. It does require a lot of work and focus. Did you verify all those cases yesterday?
I don’t know for sure. I guess so.
What about the design of the code? How did you manage to get some feedback there?
Uhm, I didn’t. I just added the code, and it looked just fine to me.
Do you mind we pick up where we left off yesterday? How about we try to add one test for verifying whether the URL is build correctly.
Shouldn’t we get going on the next user story?
We do have some time to add a single unit test, don’t we?
I guess so.
Can you try to add the test?
— After a short while —
So, now we have a test that verifies whether the URL is build correctly. It seems to pass as well. However, … it does seem to involve a lot of code compared to the other test methods that we already have. There’s a lot of setup code and then there’s also this “hack” that we needed in order to get the test to pass.
How could we improve this?
I’m not really sure …
How about we just add another test for when the condition of that if-statement evaluates to true?
OK. Let’s do that!
— After another short while —
The amount of setup code for these tests really starts to bother me. How about we just move the implementation for composing that URL to a separate class?
What’s your reasoning?
Then we don’t need the overhead of setting up the entire controller just for testing the implementation that builds the URL. Composing the URL is just some data in, and the URL comes out. We could more easily test this in isolation.
Excellent idea! Let’s try that. Can I make one suggestion?
How about we revert all the changes that we’ve made thus far?
You want to throw away the unit tests that we just added? Why?
For starters, I don’t really trust them.
Why don’t you trust the tests that we’ve added? They do seem to work and pass correctly.
They sure do. However, do they fail correctly as well? What I mean by that is whether they fail for the right reason?
Why shouldn’t they?
We didn’t see them fail. Right?
Let’s just revert our changes.
Are you sure about that?
Definitely. We’ve learned enough by experimenting. Let’s get rid of them.
Done. What’s next?
Let’s write a failing test for that class you’ve mentioned earlier. You know, the class which composes URL’s.
So we’re back at writing our tests first?
Yes, we are.
Shouldn’t we just copy and paste the code from the controller method into a new class?
In that case, we’re back to adding tests after the fact. Then we don’t know whether those tests would fail for the right reason or not.
I guess so. So we’re going to rewrite the code again?
Yes. You can consider it as a refactoring exercise. First we’re going to use TDD to drive the implementation of the URLComposer class. After that, we’re going to remove these fifty lines of code in the controller method. Then finally, we’re going to add another failing test to the test suite of the controller. You know the drill.
Let’s get started then.
— After a while —
This code definitely looks a lot cleaner now. Good thing that we performed this refactoring. Otherwise, we wouldn’t have discovered those two bugs that existed in the untested implementation.
I always have this feeling TDD slows me down too much. But not this time.
I can’t really explain it. Usually, everything seems so obvious and simple to the point that it feels that we’re just wasting time. Then again, we’re not. We’ve now spent less time reimplementing the URL composition compared to the time I’ve spent yesterday evening. How come you never seem to be stressed out while working on a user story?
Because I work as fast as I can, but as slow as I need to.
So, let’s move to the next user story then!
Almost. Now, regarding that mapper class you’ve added yesterday evening …
If you and your team want to learn more about how to write maintainable unit tests and get the most out of TDD practices, make sure to have look at our trainings and workshops or checkout the books section. Feel free to reach out at email@example.com.
Jan Van Ryswyck
Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.
- Behavior-Driven Development
- Concurrent Programming
- Continuous Integration
- Core Skills
- Design Patterns
- Domain-Driven Design
- Event Sourcing
- Fluent Interfaces
- Functional Programming
- Object-Relational Mapping
- Open Source
- Software Design
- Test-Driven Development
- Visual Studio
The opinions expressed on this blog are my own personal opinions. These do NOT represent anyone else’s view on the world in any way whatsoever.
Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Author of written words. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.