Back to Home

Revitalizing Dinosaurs: TDD vs Test-Last

test-driven development · software testing · behavior driven development · tdd · bdd · tap · test anything protocol · kent beck · martin fowler · extreme programming · test first

Revitalizing Dinosaurs: TDD vs Test-Last

    image
    Simon Stålenhag - Tyrannosaurus (http://www.simonstalenhag.se)
    “Be careful using the following code - I just proved that it works, but I did not test it” Donald Knuth
    The “First Test” technique (Test-First Design, further TFD) appeared along with extreme programming (Extreme Programming, further XP , by the way, this abbreviation is not related to Windows ) and is one of the main approaches of this methodology. The first book mention of this technique was in Extreme Programming Explained 1999 K.Beck

    image

    The technique is based on a simple idea -  before doing something, write a test on it .
    “Never write code without a fail test.” Kent Beck

    Later, the TFD technique evolved into the Test-Driven Development (TDD) technique , which took its place in the XP approach list.

    1. Development is carried out in short cycles.
    2. The implementation of the function is preceded by a failure test (red-green refactoring) .
    3. There is only one failure test .
    4. The implementation of the function should be as simple and sufficient as possible to pass the test (closely related to the principles of KISS and YAGNI ).
    5. After passing the tests, we start ruthless refactoring (at this stage we get rid of duplicates, it is closely connected with the DRY principle )


    image

    I will not retell Kent Beck 's excellent work here , for those who want to understand the TDD approach in more detail, the direct road to the store for this book ( Test Driven Development: By Example 2002 K.Beck ):

    image

    TDD not working?


    TDD is a dinosaur. But this is by no means a kompognat, it is rather an apatosaurus. Not less. Many years have passed since the description of the technique. For information technology, this is a really long time.

    The most progressive figures in the world of software development have recognized and still recognize that TDD is a very effective tool in the arsenal of a programmer. This is not a “silver bullet” , but time has proven that it works. My humble opinion is that development through testing is a brilliant technique.

    However, the situation of the Belarusian (or some other similar) outsourcing in this regard is sad. We never had a TDD. No one ever sang his odes. On the contrary, I constantly heard something else.

    In 2010, I joined the staff of QA at * instinctools. When I started to dive deeper into automation, I started asking questions: “Why our developers do not write tests?” The answer was probably obvious - the customer does not pay money for this.

    The world, like the Belarusian outsourcing, is evolving, now even a newly minted junior developer or customer far from programming knows that tests are necessary. It is difficult to imagine the auto industry or the food industry without testing (everyone would then be poisoned by food or crash on the roads), although this could also be saved. But if everyone has already come to the fact that it is necessary to write tests, then there is still no way to do this.

    It is expensive. This will not be bought by the customer. We don’t have time for this. We know that this is good, but we have too tight deadlines. Similar functionality cannot be tested with this approach. This only works for unit tests. Typical answers to the question: “Why not TDD?” .

    And at the same time, everyone writes tests all the same, but only do it in the Test-Last style .

    We don’t have time for this


    Embarking on the Test-Last path, a developer loses a bunch of TDD benefits.

    Time is increasing. It is a fact! I don’t know why, but people think that TDD drags more time. However, when the Test-Last programmer evaluates the task, the question immediately arises in his head, how much more to throw so that I can cover it all with tests and technical documentation .

    Test-Last is, in fact, a step back to the cascading model. After you implement all the functionality, you will no longer be able to achieve full test coverage, since the tests will not be end-to-end. Your testing will be superficial, I'm sure you will even adapt in the tests to the code already written. Attempts to test in depth will drag the time for the implementation of stubs.

    Therefore, for testing encapsulated mechanisms, you are likely to wave your hand.

    image

    In contrast to this technique, you can start using TDD. Thanks to TFD and end-to-end testing, coverage will strive for 100%. When developing a function, you will go through two stages: interface design and implementation . At the stage of writing the test, you need to understand what the interface of your function will be, what it will receive at the input and what it will return. What will be the format of the input and output data. Having designed the interface and writing a failed test, you write the simplest implementation, the limitations of which are already set in the test. This is the way to easy and readable solutions. You just have to describe the function in the project documentation.

    image

    And you can definitely say that in the beginning, you are unlikely to win on time. But from function to function, from project to project, the situation will change. You will hit your hand and testing will no longer be a separate development stage. It is as if merged with it. Those. it will be just development. Automated testing is not added to the evaluation as a separate item; it is already embedded in the evaluation of coding.

    “Focus on quality, and productivity comes next.”
    Capers Jones, from Mythical Man-Month, 1975


    Take the time to debug and run the application for verification. Debugging and verification of the implemented function is done through tests. By the way, this is the fastest way.

    A couple of months ago, I sat down together with Dima Santotsky (our GUI developer) to implement a graphical component form for editing the essence of the project in the program being developed. Prior to that, he had not worked in that style. From the beginning to the end of the implementation (this is the logic, there was no layout) we switched only between the console and the IDE. As a result, Dima noticed that we opened the browser only once, at the very end, for a control check of the functionality. It really is magic.

    We did not collect the client part after each change, we developed it through tests.

    Over time and everyday practice, the value chart will take the following form:

    image

    However, I see that few people want to invest in this. Due to the outsourcing model, I have come across many companies and customers, I know what I'm talking about, and this is not about anyone specific. Do not take to your personal account. At the same time, I believe in individual teams of programmers who actively apply this approach.

    Archery is far from easy. If you give it in your hands, you will hardly immediately hit the bull's-eye. Need a workout. I remember the first time I tried to shoot, the arrow flew off somewhere quite past. The instructor was afraid that I would not overwhelm any fisherman.

    Riding a car after the first lesson in a driving school is also unlikely to succeed. Same thing with TDD. From turtle races, over time, through training, you can get to Formula 1.

    This only works for unit tests.


    Integration / System Tests: I / O-First


    The hype of 2014 around “TDD is Dead” is attractive. I admit there must be compromises. Emulating a video stream in tests is extremely difficult (especially when there is no implementation of a function that processes this stream). Or, for example, to observe the approach to security testing ( security testing) Information technology is developing rapidly. Augmented reality, blockchain, computer vision - automation has a number of challenges. But I beg you, if you are implementing a simple server with CRUD operations, then writing integration tests in the TDD style will not be difficult. You know which HTTP verb a particular operation needs, you know what status should be in the response. Consider the format of the HTTP response. And the failure test with 404 error is ready. Now proceed with the implementation of the endpoint. No excuses or complications from scratch. In the case of system tests, it is important to determine the input and output data, this is the most difficult, then the process is no different from unit tests. On the topic, there is a series of video meetings from the authors of the approach with the opposition represented by DHH .

    E2E: PageObject-First (POF)


    Acceptance criteria ( acceptance criteria ) most often take the form of functional or end-to-end tests. And in this part, almost all developers do not understand how to write a test on a page that does not exist yet. Before my eyes immediately tons of HTML markup and CSS layout. This is a common mistake for beginners. The functions of the page, controls, content are important, not the layout and layout. Just as a designer creates a page layout, a developer must describe a page with a PageObject template based on design or sketching. This is the stage of real design. You decompose the page by breaking it into elements and describing them with class methods. I would call this PageObject-First technique ., and remember, the test is a failure, we do not need to know at this stage the specific ways in which we will find the controls, they are implemented later. In this part, you can still develop in the style of TDD. There is even an established name for such a practice: “Acceptance Test – Driven Development / ATDD” . There are other variations (I think that such abbreviations can be riveted every day, the essence is the same):

    • “Customer Test – Driven Development / CDD”
    • “Story Test – Driven Development / SDD”

    It is expensive


    Tests should be on all fronts and rear, but there should be common sense in everything. Automation is not a panacea; you should not get carried away with it. It should be understood that most of the tests, and these are unit tests, are written by developers. The share of automation testers is much smaller. Of course, everything is based on the allocated budget, the customer rules the ball. In this case, it is always better to be guided by the testing pyramid .

    image

    How else can you save? Let's cut back on documentation time, but at the cost of what? Why not make tests documentation?

    A new (in fact, not so new) extension of the TDD approach solves this problem. By incorporating Eric Evans' best Domain-Driven Design principles , TDD has evolved into“Behavior-Driven Development / BDD or Specification-Driven Development / SpecDD”

    Dan Nors first described this approach in 2006 , presenting it later at a 2009 conference in London. He also created one of the first frameworks based on this approach. The idea is in the title. And let's turn our tests into a specification. Those. Now, when we write a failed test, we do it through DSL (Domain-Specific Language) , incidentally describing the behavior of the developed function in a language accessible to everyone.

    image

    image

    The beginning of this beautiful idea was laid back in 1987 in the Perl language in the form of Test Anything Protocol (TAP). One of the first implementations of human-readable test results, in fact, reports.

    image

    The BDD approach turned the tests into both documentation and a human-readable and easily understandable report for the manager or customer. This idea is simple and no less ingenious than TDD.

    image

    Test last



    image

    So what about Test-Last? Is this a moss-covered story? Waste that needs to be thrown away?

    I do not think so. For me, this is an integral part of TDD. Sounds weird, doesn't it? Yes exactly. I consider Test-Last a zero step in TDD . It is with this technique that I advise everyone to start. After all, everything is known in comparison. Only those who worked in this style, and later switched to TDD, can realize the full value of Kent Beck's ideas. Young Jedi need to be on both sides. If you are currently working in the style of Test-Last, then continue. I'm serious. Try to achieve the fullest possible coverage, isolate tests, write stubs and try to reach the most hidden functions. When evaluating and planning, consider by eye how long it takes to implement the tests.

    A new project, try starting to develop in the style of TDD.

    ***


    If you have any comments or additions, I will be glad to see them in the comments or write to [email protected]

    Read Next