What is TDD? [Roadmap to Implement TDD in Your Organization]

Development Practices

What is TDD? [Roadmap to Implement TDD in Your Organization]

Programming is demanding. One can get good at it after consistent efforts for months and years. At best, development team mistakes lead them to write the code that won’t compile. At worst, these mistakes lead to bugs that do the most damage.

Wouldn’t it be cool if you have a technique that can virtually eliminate the need for debugging, and alerts you to programming mistakes after you’ve made them?

There is such a tool or rather, a technique. It’s test-driven development, and it actually delivers these results. 

Let’s take a closer look at Test-driven development. The blog is divided as follows:

What is Test Driven Development(TDD)?

Test-driven development is an iterative development process. In TDD, developers write a test before they write just enough production code to fulfill that test and the subsequent refactoring. Developers use the specifications and first write test describing how the code should behave. It is a rapid cycle of testing, coding, and refactoring.

The key ingredient for being effective with test-driven development is understanding what it truly is. I find that there are a lot of misconceptions around how to do TDD properly. TDD is one of the practices that if you do it wrong, you often pay a hefty price.

TDD means letting your tests drive your development (and your design). You can do that with unit tests, functional tests, and acceptance tests. It leads you to create very different kinds of tests that tend to be more resilient to change in the future because you’re verifying behaviors rather than testing pieces of code. Let’s see how it’s done by following three stages of test driven development.

Steps of Test Driven Development

Step 1: Create a test and make it fail (Red)

  • Write the unit test for the function you’re going to implement, the unit test should be short and focus on a single behavior of a function.
  • Write just enough code so that it compiles.
  • Run the test. It should fail. By writing the failing test you ensure that your test is calling the correct code and that the code is not working by accident. This is a meaningful failure, and you expect it to fail.

Writing a failing test, before writing the code may seem counter-intuitive, time-consuming or even “tedious” at first. But we urge you to think of it this way:

  • The test is the question you are asking. 
  • Your code is the answer to the question. 
  • By having a clear question, you can always check that your code is working, because it consistently gives you the same answer(s) … no surprises, even when you’re working with a large, inter-dependent code base!

Step 2: Make the test pass by any means necessary (Green)

  • Write the minimal code to make the test pass.
  • You are done for the particular code if the test passes as expected. You do not have to write more code with uncertainty.
  • Run your test again, and watch the test pass. This will result in a green progress bar.

Step 3: Refactor

Once your test passes, you can now refactor without worrying about breaking anything. Review the code and look for possible improvements to keep the code clean.

  • Remove duplication caused by the addition of the new functionality.
  • Make design changes to improve the overall solution.
  • After each refactoring, rerun all the tests to ensure that they all still pass.

Repeat the above steps for further development.

what is tdd

Test Driven Development(TDD) and Agile Approach

Test driven development (TDD) is one of the common practices of Agile core development. It is acquired from the Agile manifesto principles and Extreme programming. Let’s see how TDD fits well in the agile development process. 

What’s agile development? In the simplest form, It is Feedback Driven Development.

And, Feedback is Critical.

The requirements you start with may change during the development cycle. If your objective is to build what your customers wanted, you will fail—you need to build what your customer still want, what’s relevant. For you, below two types of feedback are equally important:

  • You want rapid feedback
  • You want to avoid Whack-a-mole software

Agile development is not about running fast… It is about running fast in the right direction at a sustainable pace. 

And, TDD is a way to get rapid feedback. 

“Test First,” in which unit tests are written before the code, can mitigate bottlenecks that impede quality and delivery. The test helps to define what the code is meant to do, providing guidance for the developer in terms of user functions. This concept is a natural fit with Agile in two ways: 

  1. By developing the tests from the requirements, rather than the code, communication increases. The creator of the requirements, the developer, and the tester must collaborate on the tests and the subsequent code, thereby increasing everyone’s understanding of the work at hand.
  2. By having the test or test suite written first, there is no need to wait for the testing to be done. The code can be written and tested immediately, especially when automated testing is included in the process (considered a best practice). If the code fails, it can be pushed back onto the backlog, and if it succeeds, the next item can be started.

As you evolve the system based on feedback, bug fixes, and additional features, it tells you that the code worked and continues to work as expected.

Popular Test Driven Development Tools

Following are some common and most used unit testing frameworks/tools that support TDD approach.

  • csUnit : An open source unit test tool that offers a TDD unit test framework for .Net projects
  • DocTest: A very simple, easy to learn unit testing framework for Python
  • JUnit: A Java TDD unit test framework.
  • NUnit: This one again is used for .Net projects
  • PHPUnit: This one is used for PHP projects
  • PyUnit: A standard unit testing framework for Python
  • TestNG: A testing framework for Java, which overrides the limitations of JUnit.
  • RSpec: A framework for Ruby projects.

Benefits of Test Driven Development

Code Quality

TDD encourages the development of simple, clean and meaningful code. The discipline of following TDD would naturally develop habits that lead to better code as part of developers’ everyday practice. 

Developers become more focused on the system requirements by firstly asking themselves why a feature is needed before proceeding with the implementation. By this process, the developer can identify badly defined requirements as producing a unit test for them becomes taxing. 

TDD helps developers towards simple designs; keeps things typically OO [Object Oriented] structured; pushes developers towards separated components.

Application Quality

Another advantage of writing breakpoint tests before production code is that developers spent more time designing the boundary cases needing to be covered by these tests, compared to the traditional approach. It results in more thorough testing and fewer defects at the end of the development cycle.

Increases Developers’ Productivity

TDD improves the speed as developers don’t need to spend time in debugging. It may

increase the time spent on developing tests and production code during early phases. But as the development progresses, adding and testing new functionality will be quicker and requires less rework. It’s a lot cheaper in terms of resources to fix the issue immediately rather than months down the track when they may be discovered.

It is frustrating to write 15 tests but it’s more frustrating to not be able to change something or not to know your changes are safe.

Higher Test Coverage

Higher test density and test coverage are by default advantages of TDD. In the traditional approach, there is a higher likelihood that testing would be left out or restricted to critical functionality, particularly if time was short. On the other hand, TDD institutes the discipline of all functionality being associated with a set of automated unit tests. This results in more tests and higher test coverage of the code. 

Living Documentation

Tests can serve as documentation to a developer. If you’re unsure of how a class or library works, go and have a read through the tests. With TDD, tests usually get written for different scenarios, one of which is probably how you want to use the class. So you can see the expected inputs a method requires and what you can expect as an outcome, all based on the assertions made in the test.

This can help increase developer understanding of parts of the system and therefore helps to support collective code ownership. As a result, changes to code can be made by any developer rather than the only developer who understands the code.

Limitations of TDD

Despite its advantages, many dev teams face difficulty to adopt TDD effectively. Developers often have trouble knowing where to start or what tests they should write next. Sometimes TDD can lead developers to become too detail-focused, losing the broader picture of the business goals they’re supposed to implement. 

Some teams also find that the large numbers of unit tests can become hard to maintain as the project grows in size. In fact, many traditional unit tests, written with or without TDD, are tightly coupled to a particular implementation of the code. They focus on the method or function they’re testing, rather than on what the code should do in business terms. Let’s understand this problem with an example. 

Suppose Paul is a Java developer working on a new financial trading application in a bank. He has been asked to implement a new feature to transfer money from one account to another. He creates an Account class with a transfer() method, a deposit() method, and so on. The corresponding unit tests are focused on testing these methods:

public class BankAccountTest 
{
@Test
public void testTransfer() {...}
@Test
public void testDeposit() {...}
}

Tests like this are better than nothing, but they can limit your options. For example, they don’t describe what you expect the transfer() and deposit() functions to do, which makes them harder to understand and to fix if they break. They’re tightly coupled to the method they test, which means that if you refactor the implementation, you need to rename your test as well. And because they don’t say much about what they’re actually testing, it’s hard to know what other tests (if any) you need to write before you’re done.

Now, here comes the Behavior Driven Development(BDD) as a solution. Let’s understand BDD and how it addresses the above problem.

What is Behavior Driven Development(BDD)?

BDD was originally invented by Dan North in the early to mid-2000s as an easier way to teach and practice Test-Driven Development. TDD, invented by Kent Beck in the early days of Agile. BDD differs by being written in a shared language, which improves communication between tech and non-tech teams and stakeholders. In both development approaches, tests are written ahead of the code, but in BDD, tests are more user-focused and based on the system’s behavior.

BDD focuses on the acceptance criteria from the inception by defining how each feature of the application should behave from the end user’s perspective. BDD provides a common language based on simple, structured sentences expressed in English (or in the native language of the stakeholders). BDD involves tight collaboration and communication between product owners, business analysts and the development team (including testers) to discover, understand and formulate real business needs.

Now, let’s continue with our example to see how BDD helps developers to overcome limitations of TDD. Here Paul could write more descriptive tests along the following lines in BDD style:

public class WhenTransferringInternationalFunds 

{

    @Test

    public void should_transfer_funds_to_a_local_account() {...} 

    @Test

    public void should_transfer_funds_to_a_different_bank() {...}
    
    ...

   @Test

   public void should_deduct_fees_as_a_separate_transaction() {...}

   ...

}

Tests that are written this way read more like specifications than unit tests. They focus on the behavior of the application, using tests simply as a means to express and verify that behavior. Tests written this way are much easier to maintain because their intent is so clear.

TDD vs BDD

TDD works satisfactorily, as long as the business owner is familiar with the unit test framework being used and their technical skills are strong enough, which is not always the case. In these circumstances, BDD has the advantage because the test cases can be written in a common language used by the stakeholders such as English. This access to clearer, low-jargon communication is probably the biggest advantage of using BDD, making it possible for collaboration between the technical and non-technical teams to run with improved efficiency.

TDD (Test Driven Development) BDD (Behavior Driven Development)
Focuses on the developer’s opinion on how functions of the software should work. It is basically a programmer’s view.  Focuses on the user’s opinion on how they want the application to behave. It is basically a customer’s view.
A Low-level approach As a user approach
Verifies whether the implementation of the functionalities are correct Verifies whether the application behaves the way the user wants it to behave

Is TDD worth?

TDD is a practice highly dependent on personality. Some people love to write every item down on a list before shopping and cross them out one by one in the process. While others just try to remember things and grab on site. It’s hard to justify the trade-offs, and that’s highly dependent on the scope of a task (usually flexible too).

At Simform, we follow agile methodology(which includes TDD & BDD) to build robust custom applications for our clients. Contact us to know more about the development process and how we can help you to build with app development.

Working from last 8 years into consumer and enterprise mobility, Hardik leads large scale mobility programs covering platforms, solutions, governance, standardization and best practices.

Leave a comment

Your email address will not be published. Required fields are marked *

Simform Blog

Subscribe to our TDD updates

Like what you're reading? Subscribe to get our latest updates on Test-driven development! No spam, only high-end resources directly into your inbox! 

You have Successfully Subscribed!