4th Chapter Test
Writing unit tests is a validation, but a design. Again, it is writing documents. Writing unit tests has ended many feedback loops, especially for functional verification.
4.1 Test-driven development
Let's say we follow the following 3 simple rules:
(1) Do not write any product code unless you have written a unit test that cannot be passed.
(2) As long as you write a unit test that causes the test not to pass or the compilation fails, it is enough, no more.
(3) Just write the product code that will pass the failed unit test, no more.
If we follow these rules, we are working in a very short iteration cycle. We just write the unit tests that just can't be passed, and then we write the product code that just makes the unit test pass. We alternate between these steps at a 1min, 2min rhythm.
The first and most obvious effect is that every function in the program has a test to verify its correctness. This test suite can provide support for future development. In any case, if we neglect to destroy some of our existing functions, it will sign us. We can add functionality to the program, or change the structure of the program without worrying about breaking important things in the process. The test tells us that the program still has the correct behavior. In this way, we are more free to improve the program.
A more important but less obvious effect is that writing tests first can force us to use different observation points. We must observe the program that we will write from the vantage point of the program caller. In this way, we will pay attention to its interface when we focus on the function of the program. By writing tests first, we can design software that is easy to invoke.
In addition, by writing tests, we force ourselves to design the program to be testable. It is very important to design for easy invocation and testability. In order to be easy to call and testable, the program must be decoupled from its surrounding environment. Thus, first writing tests forces us to release the coupling in the software.
Another important effect of writing tests first is that testing can be a very valuable document. If you want to know how to invoke a function or create an object, a test will show you. Testing is like a set of examples that help other programmers understand how to use code. This document is compiled and can be run. It is kept up to date. It doesn't lie.
4.2 Acceptance Test
Unit testing is necessary, but not sufficient, as a validation tool. Unit tests verify that the small components of the system work as expected, but they do not verify that the system as a whole is working correctly. Unit testing is a white-box test (White-box test) used to validate a single mechanism in the system. Acceptance testing is a black box test (Black-box test) that verifies that the system meets the needs of the customer.
Acceptance testing is written by people who do not understand the internal mechanisms of the system. These tests can be written directly by the customer or written by business analysts, testers, and quality assurance experts. Acceptance tests are performed automatically and are usually written in a specific specification language that is more suitable for non-technical people to read and use.
Acceptance testing is the final document on an attribute. Once the customer has written an acceptance test that validates a feature, the programmer can read those acceptance tests to really understand the feature. Therefore, the acceptance test is a compiled, executable document about the characteristics of the system. In short, acceptance testing is a real requirement document.
In addition, first writing acceptance tests has far-reaching implications for the architecture of the system. In order to make the system testability, it is necessary to decouple the system at a high level of system architecture. For example, in order for an acceptance test to gain access to business rules without a user interface (UI), the coupling between the user interface and business rules must be lifted in a way that satisfies that purpose.
At the beginning of the project iteration, the temptation to conduct acceptance testing by hand. However, this makes it unwise for the early iterations to lose the power to decouple the system from the need for automated acceptance testing. When you start the first iteration, it is very clear that you will have to make a very different system architecture tradeoff if you are well aware of the need to automate acceptance testing. And, just as unit testing can motivate you to make good design decisions in small ways, acceptance testing can lead you to make good system architecture decisions in large areas.
We haven't written any code yet, and we haven't done any design. This is the best time to start considering acceptance tests. Programming based on intent is once again called a useful tool. We should write them in the way we think the acceptance tests should be, and then we can design the system accordingly.
We wanted to make the acceptance tests easy to write and easy to change, and I wanted to put them in a collaboration tool that could be accessed through the internal network so that they could run at any time. You can use the Open source FitNesse tool. In FitNesse, each acceptance test can be written as a simple Web page and accessed and run from a Web browser. More about FitNesse is not covered here.
Conclusion
The simpler the test suites run, the more frequently they are run. The more tests run, the faster you will find any deviations from those tests. If you can run all the tests multiple times a day, the system will not expire for more than a few minutes. This is a reasonable goal. We will never allow the system to regress. Once it is working at a specific level, it must not be reversed to a slightly lower level.
However, validation is only one of the benefits of writing tests. Both unit and acceptance tests are a form of documentation. Such a document can be compiled and executed. Therefore, it is accurate and reliable. In addition, the language in which the test was written is clear and very easy for its viewers to read. Programmers can read unit tests because unit tests are written in a programmer-programmed language. The customer is able to read the acceptance test because the acceptance test was written in a simple tabular language.
The most important benefit of testing is its impact on architecture and design. To make a module or an application testable, it must be decoupled. The more testability it is, the weaker the coupling relationship is. Comprehensive consideration of acceptance tests and unit tests has a far-reaching positive impact on the structure of the software.
Excerpt from: "Agile Software Development: principles, patterns and Practices (C # Edition)" Robert C.martin Micah Martin
Agile Software Development: principles, patterns and practices--the 4th chapter test