Continued. Start here .How to use all this?
Good question. We stopped at the fact that TDD helps to clearly define the boundaries of the current task, provides an easy way to simultaneously work with small details related to the problem, and provides quick feedback to the code, telling how well the resulting solution is. These facts will help us overcome the difficulties in studying this technique.
What tests to write?
The simplest (albeit accurate) answer is to do any tests that allow you to evaluate classes and design further. But this answer is bad for beginners, so you have to go into details.
What I personally had to struggle most with when studying TDD was the transition from simple examples to using TDD in real projects. Choosing a test for a class lower in the hierarchy, I got difficulty inserting the resulting code back into the project. The problem here was that I did not think of tests as a way to find out what I really needed. And only when using a test that describes a solution to the problem, really useful abstractions were obtained. The trick is to create tests that encapsulate knowledge about the current problem.
')
Let's look at a more pronounced case. Let's say we have a completely new project. So we don’t even know which classes we will need. How to use TDD to learn something about the future structure of classes, when there is no class at all? Let's write a test describing the developed functionality (or script). This will be an acceptance test rather than a unit test. Nowhere is it written that TDD is based solely on unit tests, but most newbies think that the process is based on them, and further misunderstanding follows from this. So, this approach allows you to create a basic skeleton of the application, which will continue to develop and grow into flesh. Tests will assess how well we were able to divide the required functionality into controlled, tested abstractions. In addition, we will get an excellent interface to the system, which will be useful in the future when creating integration tests.
This book is an excellent source of examples
(referring to the Growing Object-Oriented Software Guided by Tests book on the so-called London School of TDD, which adheres to the “out-in” approach with the use of mocks for still unimplemented classes).Once we have defined the basic behavior of the functional through the acceptance test, we create the infrastructure required for the test (building, continuous integration), and proceed to more specific tests to highlight the internal classes of the application. Perhaps this is not needed - the direction specified by the acceptance tests will be sufficient for the implementation of the functional.
But you just wrote the code without first creating the test!
Easily. TDD provides feedback to the code. When you already know what exactly is needed (for example, if the job is to complement small parts of the finished architecture), that part of the TDD that is responsible for the design does not provide much benefit. The only advantage of pre-writing tests here is that you can make sure that they do not work initially; This is a way to test the tests themselves. In this case, the “first tests” approach is a technique for creating code covered in tests, not design.
The fewer unknowns, the fewer tests you need to find them and you can move in long strides.
Here again - using the MVVM pattern, you created a presentation without a preliminary test!
We have already learned that TDD limits the current task, as well as provides an opportunity to understand how good its solution is. Of course, TDD is far from the only way to get both the first and the second. View creation technologies (WPF, MVC frameworks, GTK, WebForms, etc.) themselves impose significant restrictions on the code in terms of interaction with the UI.
When using view selection patterns, such as MVVM, we can define the necessary properties and commands for the ViewModel without any tests. We are limited to the chosen technology of building the interface, as well as the external design, worked out during the discussion (which is also a tool that provides quick feedback) with the customer.
So TDD is not the only way to limit the task and get an estimate of the solution. Where real conditions exist, we should not ignore them and invent artificial ones.
Note: I had difficulty trying to recreate the presentation patterns by following the principles of TDD: how is it possible, using only tests, to get MVP, MVVM, etc? I think that this is difficult due to the fact that on the one hand, we have an absolutely real UI-toolkit, and on the other - only imagination and tests. There are factors that do not arise from tests, but are equally important sources of information. If someone managed to get a pure branch of the presentation only with TDD, please let me know.
I am stuck! Stuck in the tests and I do not know what to do ...
This has happened to me so many times that I hesitate to talk about it. Coming up with tests for each line of code, including those that appear in the process of refactoring, in the end I found myself in a maze of meaningless abstractions. Remember, TDD is not a substitute for thinking, you still need to be able to just write clean code!
If the process does not provide the necessary information, go back and try to do otherwise. Discuss ideas with colleagues. Try to work using test coverage of a higher level of abstraction. Just try other approaches - it is often easier to try out three different solutions than to theoretically identify one best thing beforehand. TDD is a good, but not the only way to limit the problem and reach a solution. Do what is needed right now to solve the problem, but do not forget to come back and try to understand the reason for the stop later.
To the note: If it was not possible to solve the problem with TDD, make a note about it before trying something else. It is important for you to understand whether this problem was not solved in principle using TDD, or you simply did not have enough knowledge. To catch the difference will not work if you surrender too quickly. Personally, following this principle led me to the discovery of such items as mocking, IoC containers, agreements, BDD, etc. (and I'm still far from complete lack of gaps in knowledge).
TDD? BDD? ATDD? What exactly do I need?
You may notice that using TDD is specific to each task (and for each developer). A variety of tasks create different design problems and require various types of feedback. This means that we should use TDD in different ways in order to get different assessments of the code being developed and use them in the development of the architecture. Such methods can be “top down” or “bottom up”. Sometimes we can rely mostly on acceptance tests. Sometimes it is better to use a large number of unit tests. Some problems are well solved with the help of tests "from edge to edge", using real external databases or services (this approach has its own subtleties, but if it provides the necessary feedback and ensures the development of the architecture, use it).
In general, there is no one right answer. The main goal is to get feedback from the code that is being worked on at the moment.
Conclusion
Although the TDD process instructions are simple, the technique itself is not. The instructions provide only the most minimal help at the start, while the hype around TDD forms completely unrealistic expectations.
We can solve this problem by trying to understand how TDD works and see the idea behind the algorithm. We see that TDD is actually a tool for limiting the task, encapsulating the design process with the abstract question “What will be the next test”, and providing an opportunity to quickly evaluate the results of our research. Essentially, TDD provides a great way to think through and iteratively develop an application design.
Having understood this, we can deliberately use TDD to get feedback from the developed code and use this information to solve design problems. We are not limited to only unit tests and constantly switch between levels of test abstraction (which is not at all in the demonstration examples of using TDD). And we easily do without TDD where there are other ways of getting feedback from the code, such as the UI branch or storage technology frameworks.
We also will not fall into despair if TTD rules cannot be applied, because we know that this technique is only a design tool, and there will always be gaps in knowledge or lack of experience that will have to be filled before it becomes possible to solve new problems. . The fact that TDD is an excellent indicator of lack of knowledge, gives a chance to replenish their stock right now. This is much better than blissful oblivion, which leads, in the end, to the failure of the deadlines for the delivery of the project, or, even worse, to the endless repetition of the same mistakes.
Designing is always difficult. TDD allows you to concentrate on design and understand how to make it better.
I hope these thoughts will open you a different view on TDD and make the process of learning this technique more simple. TDD is worth the effort. Good luck!