Test Driven Development

The Hidden Agenda Of TDD- Test Driven Development

Introduction to Test Driven Development

An agile approach to software development follows the four Agile manifests principles. It aims to deliver quickly the required code to customers at frequent internals enabling return on investment (ROI).

Quickly Code implicates-

  1. Code is thoroughly tested.
  2. Code meets the needs of the customer.
  3. Code can be changed easily.
  4. Code is clean well structured, self-documenting.

The technical practices prescribed by Extreme programming (XP) aid in creating quality code while adopting an Agile approach for software development. Test-driven development is one such practice.

Why Test-Driven Development?

As per Bob Martin – “The act of writing a unit test is more an act of design than of verification. It is also more an act of documentation than of verification. The act of writing a unit test closes a remarkable number of feedback loops, the least of which is the one pertaining to verification of function.”

History of TDD

Test-driven development was greatly inspired by a non-software quality control (QC) practice. Quality control in a non-software area is manual checks for every area of work before delivery.

The six steps of QC are

  1. “Add a check” translated to “Add a test”.
  2. “Run all checks” translated to “Run all tests”.
  3. “Do the groundwork” translated to “Write Down code that works”.
  4. “Run all checks” translated to “Run tests”.
  5. “Clean up the work” translated to “Refactor Code”.
  6. Repeat the process until finish.
Implementation phases of TDD
  • Beek and Astels proposed Test-Driven development in 2003.
  • As per Martin, Newkirk, Kess the TDD is all about the specification and not a process of validation.
  • Ron Jeffries defined the goal of TDD is to write Clean Code that actually works.
  • Kent Beck finally formalize the TDD concept as  TDD = ∑ TFD + Refactoring.
  • Kent Beek’s two rules for TDD –
    1. Developer should write new business code only when an automated test has failed.
    2. Developer should eliminate any duplication that they find.

Basic Principles of TDD

Test-driven development (TDD) is a technical practice consisting of soft development cycles where test cases covering the new functionality are written first. The code is written to pass the tests which are refactored without changing the behaviour of the code.

TDD is otherwise known as test-first development (TFD) and TDD is just the opposite of the traditional development process. Pair programming helps TDD to stay focus and object-oriented.

Developers write automated test cases (tests) before development. This means that development is driven by the tests. This ensures that no untested code goes into the software. Refactoring ensures that the code is “clean”.

The main philosophy of TDD, as mentioned by Kent Back, lies in Ron Jeffries’s phase “Clean Code that works”. TDD helps to design and develop the code in a predictable way by writing only code just enough to make the test cases pass.

Test Driven Development
Test-Driven Development

TDD works on a simple process of writing failing tests (written for new functionality) first. When code is written and refactored to make the test case pass, hypothetical coding is avoided. Only enough code to meet the functionality is written. It helps to create a simple workable code and greatly helps developers for generating a clean, clear and simple code. This code is easy to maintain.

Types of Test-driven development

Primarily TDD is of two types they are as follows:

  1. ATDD (Acceptance Test Driven Development)- In this technique, developers write a single acceptance test. Once the acceptance specification is fixed, developers write just enough code to pass the test. The goal of ATDD is to specify details, executable requirements just in time (JIT). ATDD is also called as Behaviour Driven Development (BDD).
  2. Developer TDD (DTDD) – Develop writes a single test (not a unit test) and developer himself write enough code to pass the test. The goal of DTDD is to specify the detailed, executable design a solution on a just in time (JIT). DTDD is also called TDD.

Test-Driven Development Concept

Test-driven development is a development approach where-

  1. A comprehensive suite of automated tests is maintained.
  2. No code goes into production unless it has associated tests.
  3. Tests are written first. Test cases can be written in several programming languages – Java, Ruby in several automation tools – Selenium, Watir, Windmill.
  4. Tests determine what code needs to be written.
Process Flow of Test Driven Development
Process Flow of Test Driven Development

In simple terms, TDD suggests developers write tests for new functionality or feature and then develop code to pass the tests. This post incorporates the design concepts from Agile modelling and Extreme programming which can be leveraged from Agile development projects.

Working principle of Test Driven Development

  • The developer first needs to understand the requirements to develop an automated test case and to achieve the desired result or feature.
  • Test cases are written first and are then added to the automation suites for execution.
  • When tests are written for new functionality and feature, code would not available for the same. Hence the tests tend to fail. These are called as failing tests.
  • The developer starts adding code to make the tests pass during execution.
  • When the set of tests passes, code is written for the new feature or developer refactors the new code as required to make it compliant with the acceptable standards and provides it for the next stages of testing.

These steps are repeated for any new functionality or feature to be developed.

In TDD way of developing a set of functions is often placed in a class or module. The best way to work with these classes and modules is to keep the unit small in size.

The advantages of smaller units –

  1. Easy and quick debugging – Small units will have lesser test cases. Hence even if an error is found, it is easy to debug and find the root cause of the issue in a short span of time.
  1. Quick self-documentation – Smaller units produce a small set of test cases, the report is then easy to read, understand and act upon

What are the Key Factors to adopt Test Driven Development?

Following are the key drivers for adopting Test driven development –

  1. Design compliance is one of the visible benefits of test-driven development.
  2. Code maintainability improves.
  3. Acts as a safety net when a developer performs refactoring.
  4. TDD is adopted to deliver the work in a simple way to avoid complexity.
  5. TDD can be considered as both design and programming methodology which is based on a simple rule of writing production code to fix a failing test.
  6. TDD converts normal cycle of design code – test into a sequential activity cycle of the test – code – refactor in which developer writes a test first (initially failing) and then writes code to pass it and further refactor the code.
  7. TDD offers a simple and effective technique which helps to create high-quality software through the continuous design and test process and frequent refactoring. This way, the code becomes simple, less defective, better designed and of high quality. The developer gets confidence in writing code and becomes more productive.

 

How TDD is different from unit testing?

TDD is not what is similar to unit testing. TDD and unit testing use unit testing frameworks such as XUnit ( JUnit, NUnit etc), however, the purpose and why in which it is used is clearly different.

Here is the difference between unit test and test-driven development

Unit testTest-driven development (TDD)
The unit test is used to test code in isolation.TDD is used to imagine what functionality you need in production and express what is supposed to do you before the code is actually written.
The unit test helps in validating tests and boosting developer confidence about the accuracy of the code.TDD, in essence, is used for incremental design and evolutionary design
Unit testing is aimed at testing and verifying application program. Unit testing is not used to design the application.TDD is preliminary used to design the application and its features. Rather than completely designing application in one go, it is designed to test by test in the incremental fashion.
Unit test methods test a single unit at a time.TDD may test multiple units of code.
The unit test is a bottom-up approached that answers “what to do ?”TDD uses a top-down approach that answers “how to do?”

How TDD is different from AMDD?

While TDD and AMDD both are a very new concept for a traditional developer. They may do mistakes while operating. Sometimes, it is seen they see these two as a challenge. But in the core, both model supports an evolutionary way of development.

TDDAMDD
TDD makes programming feedback shorter.AMDD makes modelling feedback loop shorter.
TDD emphasises more on detailed specification.AMDD emphasis more on better design thinking for large issues.
TDD empowers quality code.AMDD empowers quality communication.
TDD produces working software.AMDD produce a better working model by undertaking all stakeholders.
 TDD is all about coders.AMDD is all about different stakeholders.
TDD provides feedback at a granular level.AMDD provides feedback on overall, in a verbal way.
TDD outputs clean design callable and testable code.AMDD outputs the design and architectural issues and their solution before the code starts.
TDD is a non-visual (mostly) process.AMDD is a visual process (mostly).

In a team, there are members who are a visual thinker and some believe working code. So those members who prefer text-oriented design may follow TDD and visual thinkers may follow AMDD. Using AMDD the developers may create different models where TDD developers convert those models to clean code.

At the end mixing these two approaches, we get a very high-quality working system with maintainable and Clean Code that can be delivered.

How TDD is different from BDD?

BDD

TDD

BDD is written in plain English.TDD is written in a programming language.
BDD involves all stakeholders.Mostly developers are involved.
BDD focuses on the behaviour of an application keeping end-users in mind.TDD focuses on the implementation of the functionality.
Changes in requirements can be easily accommodated.TDD supports the changes but implementation is a challenge.
All stakeholders are always updated and always on the same page.Developers only concentrating on a particular piece are updated.
Works great for Medium-sized projects.Best suitable for small size projects but may scale up.

Popular principles used in TDD-

The popular principles are –

  1. KISS- Keep it simple, stupid.
  2. YAGNI- You are not gonna need it.
  3. SOLID principle.
  4. Fake it till you make it.

Test-Driven Development and Test Coverage

While developing code using TDD, the code gets tested rigorously and thoroughly. We can set some targets for lines and branch coverage. For instance, let’s say for line coverage it should be above 80% for new changes developed and for branch coverage it should be >85%.

Tools such as Cobertura should be used to measure the coverage. To measure coverage (like J2EE environment), the process described below should be followed –

  1. Write unit tests in an iterative and incremental way.
  2. Write unit tests only for the Java cover as that is new or modified for that functional release.
  3. Change the unit tests to fit the existing code before altering the code.
  4. Alter functional class.
  5. Run unit tests. A unit test should run properly.
  6. Run code coverage checker such as Cobertura.
  7. Make sure that new class line coverage is > 80% and branch coverage > 85%.
  8. Refactor the Code only when the Code Coverage is achieved.

The terminology used in TDD-

  • Red – It indicates fails.
  • Green – It indicates a pass.
  • Orange – It indicates refactor.

Important terms of TDD

Code coverage

A systematic software testing method which describes degree by which source code of any software program is tested. Most common methods of Code coverage include statement/line coverage and branch/edge coverage.

Branch coverage testing

A test method which ensures that at least once every possible branch from each decision point is executed. This ensures that the available code is executed.

Line coverage

A testing method which ensures every line of code is tested. Line coverage report gives a percentage of lines of Code of a program executed to complete the test.

Unit testing

A method which ensures individual units of source code are fit for use. Unit is considered as a function or a procedure in procedural programming while in OOP, the unit is an entire interface.

Code refactoring

As defined by Martin Fowler, Code refactoring is a ‘ disciplined technique for restructuring and the existing body of code, altering its internal structure without changing its external behaviour’. Refactoring is done to improve code readability to reduce complexity and to improve Code maintainability.

Mocking and Stubbing

The module may need to interact/interface with other modules and external resources (database/middle-tier). Mocks and stabs are used to test whether the written code works when interfaced with other module or external resources.

Stub – Stub is a class that is hardcoded to return data from its methods and properties. It is used inside unit tests to test a clear method and derives the expected output for a known input.

Mock -Mock is used to creating a simulated object in place of the actual project.

Example   

//using stub
public Customer createDummyCustomer () {
	Country country = new Country("India");
	City city = new City ("Delhi", country);
	Address address = new Address ("1234", "ABC street", city);
	Customer  customer = new Customer ("XYZ", "MNO", address);
}
@ Test
public void addCustomerTest(){
	Customer dummy = createDummyCustomer ();
	AddressBook addressBook = new AddressBook();
	addressBook.addCustomer (dummy):
	Assert.assertEquals(1, addressBook.getNumberOfCustomer());
}
//using mock
public void addCustomerWithDummyTest () }
	Customer dummy = mock(Customer.class);
	AddressBook addressBook = new AddressBook();
	addressBook.addCustomer(dummy):
	Assert.assertEquals(1, addressBook.getNumberOfCustomer();
}

The test structure of Test-Driven Development –

As the tests are the heart of test-driven development, test design needs to be taken care of. Test cases should make sure that –

  1. They are complete in nature.
  2. They are independent.
  3. They are easy to read and understand.
  4. They should depict the flow clearly.

Each test case should have the following points covered –

  1. Set up
  2. Body of test
  3. Validation point
  4. Tear down or clean up

Set up -> Create the required predefined condition to execute the test case.

Body of test -> Actual steps to perform testing. It must include the inputs, outputs and target behaviour.

Validation -> The steps to check or assert if the outcome of the test is correct.

Tear down/clean-up -> These steps are to return the application to its original state where the test starts. Tear down steps are very important to stop data or state population.

However, developers can create a common setup and clean-up logic for all their tests.

Avoid anti-patterns during test development –

  1. The test must start from a known and pre-configured state.
  2. Write independent tests and avoid interdependent tests. They all contribute to cascading false negatives. The root cause of defect detection is tough.
  3. The test should be executed fast and provide a report.

How to Apply Test Driven Development in Your Project?

TDD is an iterative and incremental procedure. TDD does not mean that developer can start working on code only after writing all the tests. A developer can first build the basic and high – level tests and once those are passed, the various other tests may be added. Duplication must be avoided while completing functionality and development.

Step – 1  Add a test

TDD is such a technique that makes sure that committed source code is thoroughly tested. In traditional testing, a failing test ensures the existence of a bug. Similarly, in TDD, a failing test ensures a triggering point to write code to cover an area.

This bottom-up approach actually gives confidence in development as TDD ensures 100% test coverage.

A well-written test can remove the necessity of documentation. The execution report can often replace the need for boring documentation. Interestingly developers do not like to read the documentation rather they want a clean and working code. TDD provides both. However, we need to note that tests or execution report is not certainly sufficient documentation. But they help to showcase the capabilities of the software.

New test gets added for every new story or task to be developed. This is the basic requirement for that particular user story. The test should be written in an automated way using various tools such as JUnit or NUnit. The developer must thoroughly understand the requirements of the story, before writing the test. This test will fail once the developer puts it on the automated framework.

Step – 2  Run test

Next step is to run the test. This helps serve two purposes.

  1. Running of test assures that new Code has been added, which is a criterion for passing the test. This also makes sure that the functionality is not already developed as part of any other story.
  2. A failing test is the first attempt towards TDD efforts. Failure in the first attempt implies that TDD development is in progress.

Step – 3  Make changes

Next, make changes in the test and add in such a way that the test passes. Passing test includes the process of writing code and making changes. To pass this test, Code written in the test should be isolated only for passing this particular test. No other code or functionality should be added.

  • The code development activity is an organic activity where the execution report aids the decision.
  • None other than developers themselves need to write test cases.
  • The development environment will provide some basic setup to compile code faster and execute test case faster. This is required to provide a rapid response for the smallest change a developer makes.
  • The components developed are consistent, cohesive and loosely coupled.
  • The tests will be very fast (small setup, a quick run, easy tear down)
  • The tests will be independent of each other so that they can be executed in any order and in isolation manner.
  • Test data should be easy to read and maintain.
  • Developers can use actual production like data as and when required they can use Delphix to mask and create production-like data.
  • Each test case is a small task of the overall goal.

Step – 4  Run all tests

In case the test does not pass in the first attempt the test must be run again. Failing in the test proves that it is not covering the functionality required by the story and it requires further changes.

The passing of tests assures that required functionality is covered. After passing the test, further changes need to be done to refactor the Code. Concept of refactoring can be described as cleaning of Code applying proper design pattern. This also assures that duplication of Code is absolutely avoided.

In one sprint we may have multiple stories. To keep adding more tests and new features of functionalities, the cycle of tests explained above can be repeated.

How to review projects Using TDD Test Diven Development Approach?

Following things can be reviewed to check if the project is really following a TDD approach:

Make sure that all the evidence listed here are available for every release and available to see in continuous integration dashboard.

  • > 10% Automated for new features (Unit testing)- Have a unit test for technology is added to Continuous Integration dashboard appropriate sections.
  • Unit tests should be written as standard (No expectations).
  • 80% line Coverage and 85% branch Coverage are achieved (On new code/ No expectations).

Opportunistic refactoring of legacy Code- Unit test will be written for untested legacy Code.

  • A unit test needs to be written for any method that is altered in a legacy class/ module of Code.
  • 80% line Coverage and 85% branch Coverage are achieved (No expectations).

Per release review of Unit test on each Component

  1. Report to detail the following –
  2. Are test being written using TDD?
  3. Has there been an increase in Testing for a Component?
  4. Defining where refactoring has occurred.

What are the tools for Test-Driven Development?

There many tools which can help in developing a perfect test-driven development. Test written in TDD is automated unit tools. There are unit test writing tools available in almost all the languages (like JUnit for Java, Cunit for C, NUnit for Net, PHP Unit for PHP and UB Unit for VB).

Tool   NameDetails
JenkinsUsed as CI server
ANTFor automating using ANT script
Cheek StyleTo cheek adherence its Coding Standards
Find bugsThe static code analysis tool, this is used to select a wide range of problems by analysing the Java byte code.
PMDIt scans the source Code and further looks for potential problems, possible bugs, used code, complicated expressions and duplicate Code.
JdependJava package dependency analyser which generates design quality metrics
CoberturaCode Coverage tool. It is used for Java Coverage analysis.
JUnitJava’s unit testing framework.
JProbeUsed for enterprise-class Java profiling.
LogmonLog monitoring tool

The misconception of TDD Implementation

The below section of the post talks about common misconceptions about TDD and different challenges faced while executing projects using TDD.

The common conceptions of TDD are as follows –

  1. TDD is a theoretical term and may not be beneficiate in actual practice.
  2. Independent or manual testing is not required with TDD. By using TDD, the user does not need independent manual testing is a myth. Independent/manual testing is always essential to obtain equal software. Myth – In TDD, we only need unit testing. Reality – TDD requires unit testing along with several other testing techniques.
  3. Myth – The unit tests covers 100% of the design specification. Reality – Unit testing may cover 50% to 60% of the design specification. But the acceptance testing team covers 100% design specification.
  4. The unit test makes 100% design specifications – unit test help in design specifications. As the developer thinks about the production code before they write the test in TDD and assume that it helps in creating detailed design effectively tests. Myth – Developers are creating 100% regression test suit.Reality – Actually no! even though it sounds great but they actually test a portion of UI test mostly happy paths and very less rainy paths. Actual testers cover all aspects of GUI testing and create a fully working regression suit.
  5. One can achieve 100% coverage using regression suits. It is observed in many agile projects that achieving 100% coverage is not possible because of the third party component or framework in the code, which might not have source code for test cases. As users might be working on legacy functionality or systems, there might be user interface which is hard to test.
  6. Myth – TDD outputs a set of test cases. Those test cases are sufficient to achieve quality. Reality – TDD produces a set of test cases but they are part of the actual testing effort. Other parts of testing should also be factored.
  7. Myth – TDD is for small project and does not scale enough to accommodate large projects. Reality – This is, however, true due to developers inability to take TDD into scale. The driving factors for this believe are –
    1. Even for a small project tests take longer time to execute.

    [Use latest CI-CD technique in a good machine].

    1. Every developer does not know how to test in TDD.

    [Skill issue – mindset issue – need coaching]

    1. Developers do not want to update TDD.

    [Create a team with a similar goal – better coaching].

The challenges Adopting and Executing of TDD Implementation

  1. Changing the developer’s mindset is challenging. Developers want to develop the Code and not necessarily like to test it. Hence in case of test driven development, writing test cases first and then develop the code in an automated way, is found challenging by developers.
  2. It is a challenge to apply test-driven development approach for legacy Code bases.
  3. Applying TDD and writing automated tests for a multi-threaded environment is a challenge.
  4. Developers feel that writing a test first and then to develop the product may slow down the development process.
  5. It is believed that it is tough to follow TDD in high-pressure work conditions or stringent timeline.
  6. It is a challenge to apply TDD in a long-running project where the Codebase is already developed without using the test driven approach. Applying TDD concepts to already developed untested Codebase is a challenge.
  7. Developers rarely estimate the effort required for TDD and this may pose to be a challenge.

Advantage of Test Driven Development

  1. Adds reliability to the development process. Once TDD is implemented in the project, if we write more tests, we become more productive. TDD test cases are directly proportional to productivity. Each line of code added is actually tested, it increases the developer’s confidence.
  2. More focused development-Test-driven development makes better sense as the main focus is to develop a better automation testing solution. Developers strive to improve their code without the fear associated with code changes. TDD can focus on customer’s need and can produce a better design.
  3. Easy Maintainance-Encourage programmers to maintain an exhaustive set of repeatable tests which may be run selectively or exhaustively with the help of tools.
  4. Faster results – It provides immediate feedback to reduced revision errors. Developers rights only the code that is required resulting in faster results with clear, comprise code. TDD does not allow to take care of exceptional and error cases. Thus, actual development becomes faster.
  5. More Reliable code– Makes programming more than due to the reliability of the code.
  6. Less time in debugging-Remove / Reduce dependency on the debugger and no postponed of debugging.
  7. Simplicity – Clean work, modular and less complex code. It also offers shorter development cycles. TDD divide the project into smaller parts (sub-tasks) as a result developer can put smaller steps forward by completing smaller sub-tasks sequentially.
  8. Improved quality – Automation is the biggest advantage of adopting TDD. However, it reduces errors. TDD generates extensible, modularized, flexible and clean code. This helps easy integration of modules. Finally, TDD generates smaller, loosely coupled, cleaner classes and interfaces.
  9. Flexibility – Flexibility is inbuilt due to quick comments, short cycles and automation. TDD helps mocking hence dependency on third party plugin software is less.
  10. Rapid Respond- Has the ability to respond rapidly to all the changing requirements.

Disadvantages of Test Driven Development

  • When automation is introduced to manual testing, we may face much-unexpected resistance from the team.
  • All forms of TDD need stakeholders to have in-depth testing skills. This is very tough in a real-time scenario.
  • Unlike the GUI mode of TDD, test-driven database design (TDDD) is not effective due to underlying tool support (even though DB Unit is there).
  • TDD is not capable of scaling up that means it is not that much effective while designing a large project. (For we need to take help from Agile model-driven development (AMDD).
  • TDD does not do full testing (functional). As a result, a separate group of testers are always needed to create the regression suit – Extra sort to company.
  • Full hearted management support is essential for TDD projects to success. It is more of a top-down approach while adopting and practicing TDD. But many times, management believes that writing test cases are waste of time, runaway and resources.
  • TDD may affected due to blind spot of the coders and heavily dependent on developers understanding.
  • Badly formatted, badly written tests (hard coded values) are prone to error and failure. They are tough, expensive to maintain. These test cases are risk prone, fragile.
  • TDD advocates lot many test cases. These excessive number of test cases needs more time to write and execute. They need additional sets of data to perform. But due to these set up actual delivery of software may get hampered.

Related terms

ATDD, BDD

Acceptance test-driven development –

  • Represents another form of TDD
  • Translates set requirements into a set of executable acceptance tests and implements code against the test.
  • Good practice to start with TDD and stability increase, move to ATDD.

Behaviour driven development (BDD)

  • Focuses or behaviour exhibited by the system rather than implementation.
  • Focuses on language and interactions used in the software development process.
  • Uses native language (like English) and the language of domain design to describe the written Code.

Share and Enjoy !

1 thought on “The Hidden Agenda Of TDD- Test Driven Development”

  1. Pingback: Learn 13 Advantages Of Magento Development For Ecommerce In Quick 20 Minutes - Tech Travel Hub

Leave a Comment

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