Test Driven Development (TDD) Background
Test Driven Development (TDD) was first introduced as a key part of Extreme Programming. In a nutshell, it involves developers creating tests that verify code requirements before the developers actually write the code to implement that requirement. TDD tests are typically implemented using unit test frameworks: either as "pure" unit tests, or as slightly less granular component tests. This paper will use the term "unit test" to refer to any test that is implemented with a unit testing framework such as JUnit, CppUnit, NUnit, etc.
Once written, each test is added to an automated regression test suite, which runs on a regular basis (e.g., as part of continuous integration). Tests will fail until the code is implementedproviding the developer a constant reminder that additional implementation work is needed. Once the test passes, code can be refactored as neededwithout fear that the refactoring might inadvertently break or change the verified functionality.
If a test failure occurs at any point after the code was implemented, this alerts the team that previously-verified functionality has been impacted by a change to the code base.
Test Driven Development and the Agile Manifesto
Test Driven Development is critical for supporting Agile Manifesto principles such as:
- Enabling early and continuous delivery of valuable software.
- Welcoming changing requirements.
- Delivering working software frequently.
Test-Driven Development Obstacles
The key obstacle that development teams face in truly adopting TDD is the time required to build and maintain the required test cases. Without process automation, time constraints allow the TDD practice to become optional.
Time constraints stem from two main sources:
- Setting up good tests can be complex: The process of writing a test that effectively verifies a requirement involves both creativity and solid coding/testing skills. The complexity of creating effective unit tests adds to the challenge: setting up the proper initial conditions for realistic unit tests can be difficult and time consuming.
- The test suite has to be kept in sync with the evolving application: Ideally, as each TDD test is created, it is added to a regression test suite, then run regularly against the evolving code base to alert the team when any code base modifications break or change the already-tested functionality. However, in order for this strategy to deliver the desired results, the team needs to keep the test suite in sync with the evolving application; otherwise, the test results will be so noisy that they will be ignoredor the entire test suite will be abandoned.
Considering the compressed nature of today's development schedules and the constant pressure to do more with less, it is not surprising that such tasks tend to get dropped unless TDD tasks are made a natural and non-negotiable part of the team's day-to-day workflow.
Parasoft and Test-Driven Development: Unit Testing & Policy-Driven Development
Parasoft addresses these obstacles in a number of ways:
- To make unit tests more valuablewe offer technology that automatically correlates requirements, tasks, code, tests, builds, developers, and artifactsas well as add coverage tracking, advanced reporting, and runtime error detection during test execution.
- To ensure that TDD practices are maintainedwe offer an automated infrastructure that notifies the developer if a unit test is not yet associated with a task or requirement.
- To facilitate unit test developmentwe offer technologies that reduce the work required to implement realistic and useful test cases.
- To facilitate unit test suite maintenancewe establish an automated infrastructure that automatically assigns each test failure to the responsible developer and distributes it to his IDE to facilitate review and response.
- To ensure that manual tasks become a continuous and natural part of the workflowwe help you implement a policy-driven process. Management expectations are set by defining what practices are required as well as when and how to apply them. Related tasks are then seamlessly integrated throughout the SDLC and unobtrusively monitored for compliance.
Unit Test Case Development
The process of writing unit tests that verify requirements is always a creative one. The developer really needs to think about the code and how to test it effectively. But automation can reduce the work required to implement realistic and useful unit test cases.
For instance, Parasoft's object repository stores initialized objects, which are very helpful to use when youre trying to set up realistic initial conditions for unit testing. Parasoft's stub library can be used to stub out external references so the unit can be tested in isolation. Also, test case parameterization can be used to feed additional inputs into the unit test cases inputs from a data source, or a stream of automatically-generated inputs using corner case conditions.
As unit tests are being developed, static analysis can be performed to check that the unit tests follow industry-standard unit test guidelines. For instance, static analysis rules check the proper implementation of unit test case:
- Test methods
- Error message strings
- Fail methods
- Setup and teardown methods
- Test documentation
Once unit tests are developed, they can be executed in Parasoft's industry-leading unit test framework. Using this framework, teams can:
- Centralize execution and reporting for all unit tests.
- Track targeted or cumulative test coverage (both unit-level and system-level) using multiple coverage metrics.
- Automatically generate additional unit tests using the TDD unit tests as a template.
- Extend the regression test suite with automatically-generated regression test suites that detect regressions in application behavior that your TDD test cases do not cover.
- Track which unit test cases failed, since when, and who is responsible for fixing each failure.
In addition, runtime error detection can be performed as the TDD and other tests execute. This is key for efficiently identifying defects that manifest themselves only at runtime (for example, file overwrites) and zeroing in on the root causes of the application crashing, running slowly, or behaving unpredictably. Categories of defects detected include race conditions, exceptions, resource & memory leaks, security attack vulnerabilities, null pointers, uninitialized memory, buffer overflows, and more.
Unit Test Suite Management and Maintenance
To ensure that unit test suite maintenance is as painless as possible, Parasoft establishes a supporting infrastructure and workflow...
To read more, download the complete Test Driven Development (TDD) and Unit Testing paper as a PDF.
Photo Credit (top image): nyuhuhuu