Friday, October 23, 2020

2.3 Test-Driven Development

 In today's agile world, software is developed iteratively. Building software step by step is far more productive than attempting to build software in large chunks. Smaller parts of code are easier to test, and testing smaller parts of code can cover more edge cases to detect and prevent bugs. This process ensures that the code satisfies the requirements. But when do you create all these tests? Test-driven development (TDD) is a software-development methodology where you write the test code before the actual production code.

TDD ensures that use cases are tested, and source code has automated tests by using the test-first approach.

Development is done in iterations, where you do the following:

  • Write tests.

  • Run these tests; they must fail (code may not even compile).

  • Write source code.

  • Run all tests; they must pass.

  • Refactor the code where necessary.



At the beginning of software development, the team defines tasks for what you want to achieve in the current iteration. By working on a specific task, you should have very accurate information about what you need to achieve:

  • Which kind of functionality you need to develop?

  • What are the input parameters for the functionality?

  • What is the expected result of the functionality?

Having this information, you should be able to create the following tests:

  • Tests for expected input parameters and expected output

  • Tests for unexpected input parameters

Writing these tests first has immediate benefits for development:

  • Gives you a clear goal—make the tests pass

  • Shows specification omissions and ambiguities before writing code, avoiding potentially costly rewrites

  • Uncovers edge cases for you to address from the start

  • Makes debugging easier and faster, because you can simply run the tests

  • Passing each test is a small victory that drives you forward.

Tests that cover all possible input parameters, especially edge cases, are crucial in software development because most bugs arise from scenarios that were not covered during the development phase. The tests that you create and run will fail because no actual code is developed yet. If these newly written tests do not fail, revise them to verify that the tests that you wrote do not have obvious bugs themselves, such as tests always passing.

The next step in the TDD approach is to develop the code that implements required functionality—the actual task. Here, you will write code and run tests, perhaps many times, until all tests pass. You have already written tests, so it is simple to run and debug the code that you are writing. Tests give you direct feedback about how much functionality you have already implemented, telling you when you are done, and keeping you focused on the task at hand.

Do not write more code than is needed to achieve your objective: getting the tests to pass. Otherwise, parts of code may be untested and will need to be maintained, even though they are not required.

When all tests pass, you can be confident that you have implemented the new functionality and did not break any other parts of the system.

When code is developed, previously created tests should pass. But even with the passing tests, development is not finished yet. At the beginning of task development, you usually do not know all the details, and you may have written code that is not optimal. Now step back, look at the whole codebase, and clean it up by refactoring. Developers usually struggle the most with this step, but it is very important.

Refactoring the code before moving to the next task has multiple advantages:

  • Better code structure: You might find out that a certain part of the code will be used multiple times, so you move it to a separate function.

  • Better code readability: You might want to split or combine different parts of the code to be more readable for other developers who are not familiar with the task.

  • Better design: You might find that refactoring the code in some way will simplify the design or even improve the performance of the software.

The TDD iteration is finished when code refactoring is done and all tests pass. Then, you can proceed to the next iteration.

This process can be applied on many levels, from fixing one-line bugs to writing functions, or even whole modules. You can apply it right at the start of development, before design, to help you detect design flaws. This way, you avoid costly rewrites because it is easier to make changes before the implementation gets too advanced.

Content Review Question

What is the first step in a test-driven development iteration?

No comments:

Post a Comment