Test-driven development is a development method that grows a product by repeating the process of "test => implementation => refactoring" over and over.
I will explain a little more in detail. Repeat the next three steps.
To think about test cases is the same to think about design. You can put in your test case what you want this object to have, how it will be used, and what results you want it to return.
What is important in this phase is NOT to think about the implementation, but to consider how it will be used.
Do a minimal implementation just to pass the test case. At this time, it is a rule that you should not think of abstraction or clean code. Just implement the test written in the first phase.
In extreme terms, if you want to pass the test
sum (1,1) => 2, the sum method implementation can be a method that just returns 2.
It is a phase to compensate for the crimes committed in the Implementation Phase. Abstraction can be abstracted, terrible variable names can be corrected, and copied pasta should be a method.
The point here is to run the tests as soon as you fix it. Make sure that all test passes while refactoring program. This allows you to refactor your code while ensuring that the behavior has not changed.
It's a very strange development method, so it's pretty hard for first-timers to find why you do that.
However, test-driven development is the basic style of agile development, and once you get used to it, you will rather think "why not test-driven?"
In this article, I would like to introduce the four reasons that I thought were important.
I think this is the easiest to understand.
Since test implementation is performed after writing the test, the test coverage of test-driven development is generally close to 100% (if the method is cut out during refactoring, it may not be tested).
More of it, Being able to think about bugs during the test writing phase also helps improve quality. Writing tests is the same to think about the time of use, so it will be easier to come up with the idea of edge cases that can occur at the time of use, such as "I want you to return an error if the value here is null". As a result, error cases may be covered at an early stage.
The implementation phase only considers passing tests that are not currently passing, so specifications that are not expressed in test cases are not implemented.
If you start with implementation without writing tests, it's common to over-abstract. Often, I thought that it might be used in the future, so I added an extra function and it was not used as a result.
Writing extra features not only reduces the readability of the code but also causes bugs.
Too much implementation is bad, but of course too little (specification omission) is also not good. If the specification can be expressed well in the test case, the implementation side is synchronized with the test, so it can be confirmed that all specifications are satisfied. The ideal is to write a test specification instead of writing a specification document. Gaps such as those described in the specification document but not implemented can never happen when the test itself is the specification.
You refactor when all tests pass.
Each time that you change one piece of code, run the test immediately to see if all tests pass.
This makes it possible to make changes with confidence because a regression test has been done to see if the changes you have made affect other parts.
That confidence boosts bold refactoring.
By taking these 3 steps
Test => Implementation => refactoring repeatedly, you can proceed with the development slowly and incrementally.
If you get stuck in the middle or break another test, you can undo it until you pass all the tests.
In other words, the test becomes a save point.
There are other benefits to developing in short steps. Humans are not good at thinking about things. When your boss suddenly says, “Make this product!”, You suddenly get thrown out over the white editor, you don't know what to start from, and you can't even take the first step. However, you can take a step forward if you write a test case and think about implementing it only, thinking that “there is such a specification first of all”. A human being is a creature that can be created by reducing problems and concentrating on them. A short step also means cutting out a scope.
I think that test-driven development with pair programming is also suitable for programming education.
A teacher writes test cases, and a learner implements them, and technical skills are improved by the teacher's guidance at the refactoring stage.
Experts can adjust the stride of the test case, so you can proceed with adjusting the difficulty.
Also, rather than solving a programming problem, it is thought that providing educational feedback while watching the process is highly educational. For programming, the process is more important than the result, and I believe that improving it will increase productivity.