Lesson 6 of 21

Common TDD Questions and Answers

Duration: 5:49 Watch on YouTube (external link, opens in new tab)

Markdown version

Why not write many tests at once? Why start with a failing test? why solve things in the simplest way (external link, opens in new tab)? These and many more questions are covered in this short talk.

In this lesson

Roy Osherove answers why tests are written before the code: to test the test (external link, opens in new tab), to think about the problem before the solution, and because there is never time to write them after the code. He says TDD (external link, opens in new tab) makes developers try to prove that their code doesn't work, that the tests remove the fear of refactoring (external link, opens in new tab), and that doing the simplest thing (external link, opens in new tab) avoids writing code nobody uses. He also explains why he has only one failing test at a time and writes the planned tests as comments.

Transcript

1,030 words

[00:06] (external link, opens in new tab) Okay. Common questions about about TDD (external link, opens in new tab). Why write the test before the code? First of all, it's about testing the test. Remember so we think through the requirements and we also look at the design of requirement and that gives us a lot of a lot of problem solving abilities. Someone wrote that TDD is an excuse to think about the problem before thinking about the solution. And I think that's absolutely true. Many times we think about the solutions and we fix the wrong problem.

[00:38] (external link, opens in new tab) And a lot of times what happens when you do TDD is that you spend much more time trying to understand what it is you're doing and why you're doing it and what's the point. A lot of times you say, "Oh, I shouldn't have built that one." So it makes you talk much more with your customers. You make it fail first so you can test the test (external link, opens in new tab). And also I forgot to say that you write the test before the code because you never have time to write the test after the code. So if you write it before you always have time to do it.

[01:11] (external link, opens in new tab) We make it fails fail first because we define one problem to solve. So, I chose one problem and then I made that pass and then another problem made that pass. I don't have five different failing tests at the same time. I have one. That's kind of the point. I don't want to have a big problem solved, just a small one. And when I do solve it, I solve it as simply as possible. And that forces me to think about new tests. Because if you think about it, as developers, we're usually very not objective about our code.

[01:44] (external link, opens in new tab) We assume that it works. So when we write tests for the code after it's passing we assume we're trying to prove that the code works. And with TDD the objective is to prove that the code doesn't work. So we're thinking much more like testers. So TDD is a good way to force yourself to think about how to break your code instead of how to prove that it works. That makes the code much more resilient in terms of quality. So the simpler solutions force you to do that to say no that's assumption is wrong let's prove that that's wrong prove that that's wrong and it also usually find that your code will be much simpler than you thought it will ever be and that's a nice thing you you start with the solution in mind but you just keep doing very very small steps and suddenly everything passes and you didn't even do half of the things that you thought you will do and that's a great feeling

[02:39] (external link, opens in new tab) The refactoring part which we haven't done yet is the the part where you make the code much much easier to read. And one example is that you constantly improve the the readability and the design of the code by extracting small methods from big methods. And if we don't do it, our code is going to be very very ugly although it will pass all the tests. And one of the nice things about having those tests as a side u as a side benefit is that because you have the tests you have no fear of refactoring.

[03:12] (external link, opens in new tab) So one of the things that always happens in projects is that people are afraid to change the code. So they copy and they create a new version of the code with the changes they would like because they don't want to break the original code. And that's how code has children. Basically, the code becomes bigger and bigger and more disgusting because everything looks like a copy of everything else because everyone is afraid to change everything. And then at some point, someone says, "Ah, let's just rewrite the whole thing." And one of the nice things with this is that you're not afraid to change the code. So, it looks like like a plant that you keep growing and trimming and watering instead of replacing the plant every year.

[03:49] (external link, opens in new tab) You're just cutting the leaves where you need to. And the incremental work is very important because usually when we over plan something we don't use all the features. So imagine using something like Microsoft Word. How many of the features of Word have you actually used? Maybe 10%. Think about all the code that you've written in the hope or in the idea that someone might want to use it. How much of that actually gets used? By studies we've seen that

[04:23] (external link, opens in new tab) 60% of the code that you write usually doesn't get used. So you're writing 60% of code that you're just wasting time on average. So instead of doing that instead of planning over planning for the future we do just the simplest thing that could possibly work (external link, opens in new tab) and that saves us from the future risks of overarchitecture and things like that. It's also a great feeling to have this passing, this passing, this passing instead of having one big feature that works after a month.

[04:58] (external link, opens in new tab) And again, I covered the idea of why not write this multiple tests at once. I might write comments of tests that I will have because I don't want to forget, but I don't have 10 failing tests at the beginning. I have one failing and then I write another that fails. I might have 10 comments but I don't have 10 failing tests. That's important so that psychologically I am focused on a specific set of problems. For example, if you have three failing tests on string calculator (external link, opens in new tab), you might be tempted to fix all of them at the same time and that would make you write code much more complicated than you would.

[05:34] (external link, opens in new tab) You might end up with code much more complicated you would have if you solved it one at a time. So by separating it, you're actually making it easier for yourself to think only on very small problems and not solve too many problems that maybe you didn't even test