Sunday 19 October 2014

TDD in Action

Background:

Software Development was shaped by 2 major influences: Procedural Programming and OO Programming. Changing Requirements demanded shorter development cycles which is impossible with traditional methods of software development like Waterfall Model. Extreme programming (created by Kent Beck) is a Software Development Methodology which is intended to improve software quality and responsiveness, taken into consideration changing requirements of the customers, frequent releases in short development cycle. Best Practices are decided as part of exploring XP and then these best practices are taken to extreme levels in XP.

Extreme programming also introduces a number of basic Values, Principles and Practices on top of the agile programming framework.
 

Values: 

Communication, Simplicity, Feedback, Courage and Respect
 

Principles:

Feedback, Assuming Simplicity, Embracing Change
 

Practices:

XP Practices are grouped under following 4 categories:

  1. Continuous Process: Continuous Integration, Refactoring, Small Releases
  2. Shared Understanding: Coding Standards, Collective Code Ownership, Simple Design, System Metaphor
  3. Programmer Welfare: Sustainable Pace
  4. Fine Scale Feedback: Pair Programming, Planning Game, TDD, Whole Team

 

What is TDD?

TDD is one among the different practices of XP. This is a Software Development Style where Testing is included as part of Software Development. Testing is initiated before Coding. In other words, automated unit tests are written BEFORE implementing a feature.
Few quotes which says the same idea are:
  • Tests DRIVE the code 
  • Test-First Approach
TDD follows the principles of KISS (Keep It Simple Stupid) and  YAGNI (You Aren’t Gonna Need It)  means Fake it till you make it

Goal:

"Clean Code that Works" by John Reffries (Founder of XP along with Kent Back & Ward Cunningham)

Process:

 

TDD Mantra:

Before writing a feature, unit tests around the feature are written. Initially all the tests will fail since code is not implemented. This stage represents RED circle in the below diagram. We write code to make all the test cases succeed. This stage represents GREEN circle. Now the question: are we done? No, not yet. Because the code/feature, that we have written or we have developed, is more inclined to customer's requirement. This code may not be production ready i.e. code duplication, inflexible solution, improper usage of design etc. To make the code efficient and maintainable, we need to REFACTOR the code which represents REFACTOR circle. After refactoring, we need to be sure that no unit test should fail. Following diagram brief about what I explained:
 

 

Benefits:

There are many benefits of using TDD approach in development lifestyle. I am mentioning only most relevant and important ones.
  1. Living, Breathing Documentation: If someone has to understand someone else's code then unit tests written as part of TDD will behave as a documentation.
  2. Quicker Regression Cycle: Most of the team faces a situation where a defect fix impacts already fixed defects that results in larger regression cycles. If the team is living with TDD approach then regression cycle will be much quicker. Also, team will be able to release more often without any compromise on quality of the software.

Unit-Testing Frameworks:

Importance of TDD can also be observed from the fact that almost all of the languages provide one or more unit testing framework even though there are many languages in the market today. Following table lists various unit testing framework supported by common languages:
       
              


Class Diagram:  

There are many approaches/ways to utilize any framework. I am explaining one simple approach to incorporate DUnit testing framework. Usage of unit tests in TDD can be understood from simple class diagram:

  



Sample:

Follow these simple steps:
  1. Write Test class which should be derived from TTestCase and define Setup, TearDown derived methods i.e. TestClass1 in above class diagram. Also write unit test cases around the functionality or class.
  2. Implement the functionality or Class i.e. Class1 in above class diagram
Following is the Test Registration class written for Vehicle Registration application: 
Actual functionality of Vehicle Registration application is:

 

Real Life Challenges in TDD:

There are 2 scenarios at a broader level where we need to think of using TDD:
 

Development of New Product:

Simply utilize Bottom-Up approach mentioned above to incorporate TDD in development cycle.
 

Existing Code (no TDD already in place):

People face this situation most of the times, when they have to maintain the existing code. From my experience, I can think of 3 approaches to bring TDD into Action:
  1. Ignore the existing project and start from scratch
  2. Use TDD for new code/functionality and legacy code which new code touches
  3. Use TDD for new code/functionality and leave legacy code as it is
There are pros and cons of each approach. Based on cost-benefit analysis among these approaches for a product, software development team can think of one of the approaches to include TDD in their Software Development Lifestyle.