What is Test-Driven Development (TDD)?
Test-Driven Development encourages simple software designs and inspires developer confidence.
You have probably heard the term Test-Driven Development (TDD) mentioned a few times and are perhaps wondering where it fits in the software development lifecycle.
Test Driven Development (TDD) is a software development approach in which test cases are developed to specify and validate what the code will do. It is an established technique for sustainably delivering better software faster.
Test-Driven Development is based on a simple idea: write a failing test before you write production code itself. Test cases for each functionality are created and tested first and if the test fails then the new code is written in order to pass the test and make the code simple and bug-free. However, this deceptively simple idea takes skill and judgment to do well.
This article will help you understand the Test-Driven Development cycle and will also highlight the benefits of Test-Driven Development.
Test-Driven Development Cycle
When applying the Test-Driven Development approach you write a failing test, write the code to make it pass, then make the code better. That set of steps has led to the “red/green/refactor” mantra where red means fail and green means pass.
Test-driven development constantly repeats the steps of adding test cases that fail, passing them, and refactoring.
The red, green, refactor cycle, by Nat Pryce.
The following sequence forms the Test-Driven Development cycle:
Write a single unit test describing an aspect of the program
Adding a new aspect to your program starts by writing a new test that will pass if the production code for that new aspect is implemented. This will help you focus on the requirements before writing the implementation code.
Run the test, which should fail because the program lacks that feature
The new test you added should fail because the code has not yet been implemented. This shows that new code is actually needed for the desired feature. It rules out the possibility that your new test is flawed and will always pass.
Write just enough code, the simplest possible, to make the test pass
Implement the new feature that you wrote a test for. At this point you should just write the bare minimal code that will make your test pass. Inelegant code is ok at this point as it will be cleaned up in a future step. Do not add any other code beyond the code that makes your new test pass. All your other tests should also now pass, if any existing tests fail it means the new code you added has broken some existing functionality. Fix any broken tests before proceeding.
Refactor the code until it is clean and simple
Clean up your code by refactoring for readability and maintainability. Run your test suite after each refactor to help ensure that no existing functionality is broken. Some examples of refactoring include:
Moving code to where it most logically belongs
Removing duplicate code
Making names self-documenting
Splitting methods into smaller pieces
Don’t skip the refactor step. Skipping the refactor step means you're not taking full advantage of what the TDD process has to offer. Having all your tests passing lets you change your code with confidence. Don't pass on this opportunity.
Repeat, accumulating unit tests over time
Repeat the cycle above for each new piece of functionality you add to your codebase. Your tests should be small and incremental. That way, if new code fails some tests, you can easily revert rather than having to debug excessively.
Test-Driven Development Benefits
Test-Driven Development brings many benefits to your software development approach. It should encourage simple software designs and inspire your confidence.
Test-Driven Development allows you to focus on writing only the code necessary to pass tests. As a result your software design can often be cleaner and clearer than is achieved by other methods. By focusing on the test cases first, you must imagine how the functionality is used by clients (in the first case, the test cases). So, you are concerned with the interface before the implementation.
Test-Driven Development can lead to more modularized, flexible, and extensible code. This effect often comes about because the methodology requires that you think of the software in terms of small units that can be written and tested independently and integrated together later.
Test-Driven Development helps ensure that your application is written for testability, as you must consider how to test the application from the outset rather than adding tests later.
Test-Driven Development helps you develop good code test coverage as it ensures that tests for every feature get written. Large numbers of tests help to limit the number of defects in the code.
Writing tests first leads to a deeper and earlier understanding of the product requirements.
With Test-Driven Development, each test case fails initially: This ensures that the test really works and can catch an error. You will have good quality tests in your codebase.
The early and frequent nature of the testing helps to catch defects early in the development cycle, preventing them from becoming endemic and expensive problems. Eliminating defects early in the process usually avoids lengthy and tedious debugging later in the project.
Conclusion
One constant in the software world is change. As your product grows and scales there will be many changes you will need to make to your codebase. The easier your codebase is to change the easier your job will be. Test-Driven Development is a great approach to help you keep your software easy to change.
Are you practicing Test-Driven Development in you day-to-day work?
Test-Driven Development Resources:
Test-Driven Development by example - https://www.amazon.com/gp/product/0321146530/
Test Driven Development is the best thing that has happened to software design - https://www.thoughtworks.com/insights/blog/test-driven-development-best-thing-has-happened-software-design
The art and craft of test-driven development - https://increment.com/testing/the-art-and-craft-of-tdd/