B
B
bagerman2015-09-05 15:01:18
Programming
bagerman, 2015-09-05 15:01:18

Where to start learning how to write TDD tests?

Hello!
There is an opinion that in order to really improve your skills and knowledge of a programmer, you need to write TDD tests.
What is it in general and what to write?
Please provide an example of these tests as they are written.
Thank you.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey, 2015-09-05
@bagerman

you need to write TDD tests.

No, there is no such thing as "TDD tests". TDD is one of the Extreme Programming (XP) techniques. You have already been given a link to Kent Beck's book on this topic (I highly recommend it by the way)
The essence of this methodology is to break the work on the code into three stages, which are called the red-green-refactoring cycle.
- Red - before writing code, we must write a test that breaks (usually broken tests are highlighted in red in the console). According to this methodology, you should write code strictly when you have broken tests. If there are no broken tests, then there is no need to write code.
- Green- when you have received red tests, you should complete the code as quickly as possible like this. so that the tests are green. Let's say if you wrote a test that expects a function to return the string "foo", then in your code you should have no more than the function itself and the output of the string "foo". As soon as we have achieved this, we either refactor or add more red tests to finish the code later. Of course, doing such primitive things in such a cycle is redundant, and Kent Beck describes the concept of "step length", that is, how much work we can do at each stage. You should always connect common sense with a word.
- Refactoring- in the previous phases, we did not drive about how beautiful our code is, how much we followed the principles of DRY, etc. so this is the code cleanup phase. We can do it every iteration, or we can do it every couple of hours, but it's important to do it as often as possible. At this stage, we eliminate duplication both in the application code and in tests. It is important to note that it is a good idea not to refactor both code and tests at the same time, because we must have a source of truth. If we cleaned up the tests and at the same time they started to fail, then we broke something while counting. And vice versa. And if you change this and that between test runs, it is not clear who is to blame.
Usually TDD is practiced using unit tests (which is logical, because they are executed quickly enough that the execution of the tests would not make us make tea), which means that we are testing one unit (one class or object), and all its dependencies must be replaced on mocks (fake objects that are needed to check how our object interacts with others, a lot has been written about this too). But no one forbids using integration / functional tests and at the same time practicing TDD (for example, dudes practicing BDD do it), and Kent Beck calls this business ATDD.
Actually TDD gives us the following advantages:
- you do not waste time designing a system on a microscopic scale, this is an evolutionary approach, the application architecture is constantly changing and evolving along with the requirements. All requirements are formalized in the form of tests.
- the code is always covered with tests (albeit not 100%, usually 20% is enough to live on, it all depends on the life of the project and the required level of reliability)
- if it becomes difficult for you to write tests (for example, many dependencies, it is difficult to mock) - then this should lead you to think about the wrong architecture and initiate a deeper refactoring. And if there are tests, it's not so scary.
- the need to cover tests increases the need to comply with all sorts of principles like SOLID, etc. because otherwise we start writing tests very inefficiently and again we return to the fact that something is wrong with the architecture.
updated
here in the comments it was caught that I did not indicate the minuses and the scope of the methodology ...
The downsides of TDD come from the upsides. This is an evolutionary approach that works well when we make changes to the system in small chunks and always refactor our code so that it is beautiful and easy to extend most of the time. If they gave you a legacy project in your hands and told you to refactor, then TDD does not fit here or it does not fit well. But again, such a task is set quite rarely, more often - adding functionality. And in this case, we return to making changes in small portions and an evolutionary approach. It's just that it will take quite a lot of time, but if we compare it with "refactoring + adding functionality + regression testing", then depending on the situation, TDD can either give a profit or not. It all depends on the complexity of the system. On simple systems, this makes no sense.
Regarding the scope ... There are several points of view. At a minimum, TDD is about architecture design, not algorithm design. This is what we do with tests. But again, it is rather inconvenient to develop certain types of projects through unit testing: compilers, translators, various solutions based on complex algorithms (for example, compression algorithms, encryption, etc.), things tied to network interaction, for example, clients for protocols. For these things, functional tests are more suitable, or they are completely difficult to cover with tests.

A
abcd0x00, 2015-09-06
@abcd0x00

TDD looks good at first glance, but then the pandemonium begins.
On the one hand, the code that is under the control of tests looks very nice, you can’t dig into it, because the tests, as it were, “clamp” it into the correct form. There is such an expression "bulletproof code". When there is a lot of such code, looking at it is a pleasure.
On the other hand, I once sat for about a month, putting tests on a future program in which there was nothing but air. And then I just lost motivation and I didn’t want to write the program anymore.
It looks like this:
One day you want to write a cool program that does this, this, and that. You, being impressed by its capabilities (in your imagination), think through all its components in your head to the smallest detail and are ready to rush into battle. You can already see this data obtained from it as a result, and you are already climbing on it, applying it here and there.
But you have to follow the rules of TDD and you are drowning in these coatings of each groove with tests from all sides. As a result, you have a lot of tests, a long history in the repository from their creation, and zero programs.
And after all the program, instead of tests to it is necessary.
Therefore, now I am making a program without tests at all (a prototype) in order to reveal all the pitfalls, and then I write tests and a new program. At the same time, all this happens under the motivation obtained from the data (prototype), for the sake of which this whole program was started.
But that is not all. Once there comes a moment when the program should not be refactored, but radically changed. (And this is the most important thing - to remove some kind of dead end in time, to which everything is heading. If this is not done, the program will be a conglomerate of plugs - and there is already an example, the tenth version.) And it becomes just a pity to erase tests that the new version does not fit at all.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question