Home > Software Quality Tips > Software Testing > Successful test-driven development (TDD) with external systems
Software Quality Tips:
EMAIL THIS
 TIPS & NEWSLETTERS TOPICS 

SOFTWARE TESTING

Successful test-driven development (TDD) with external systems


Grant Lammi, Contributor
05.19.2008
Rating: -5.00- (out of 5)


Software quality news and advice
Digg This!    StumbleUpon Toolbar StumbleUpon    Bookmark with Delicious Del.icio.us    Add to Google


Grant Lammi
Grant Lammi

There is growing sentiment that test-driven development (TDD), with its insistence on running unit tests with every compile, delivers higher quality than traditional methodologies. However, when introducing TDD, questions inevitably arise about how to write tests against an external system like a database or a Web service.

Generally, there is not a good answer to the question of TDD and external systems. If you use the actual external system, you write tests against code you do not control and that can change without your knowledge. You can still run the tests successfully with each compile, but it is difficult.

You can use mock objects to approximate the functionality of an external system, but they do not completely solve the problem. In fact, mocks can hinder TDD adoption because you have to write test code that may not map correctly to the real world.

The best solution is to think of TDD as a flexible system that does not require you to run tests at every single compile. You can write TDD integration tests but exclude them from the post-build step where they are traditionally run. This provides the benefits of TDD (better code and higher quality) while minimizing the setup. It also eliminates the need for mock objects and the maintenance associated with them.

Example: User authentication

I recently used Kerberos to add single sign-on authentication support to a Mac OS X application. The external system in this case is Microsoft Active Directory. The application creates all the various Kerberos tickets needed for user authentication and confirms the data with Active Directory.

Fixture setup
Prior to testing, I created the Xcode project for the application and the C++ unit testing framework, UnitTest++. I wrote each unit to a failure condition first and then filled in code until the functionality passed.

Example 1 shows the fixture setup for this set of tests, which is the code executed before and after every test. It includes the following:

  • The unit testing code
  • The primary Kerberos authentication object (CClientAuthData)
  • Some relatively empty fixture build up and tear down routines
  • The m_sTarget data member, which is a string that holds the name of the Kerberos service the application accesses

SUITE(CClientAuthData_Test)
{
   struct CClientAuthDataFixture
   {
      CClientAuthData testData;
      CTTString m_sTarget;
      
      CClientAuthDataFixture() 
      { 
         m_sTarget = "";
      }
      
      ~CClientAuthDataFixture() 
      {       
      }
   };

Example 1: Fixture setup

Example: Checking initialization

I wrote some simple tests to ensure that objects were created correctly. Then I created more advanced tests like example 2, which checks that the initialization fails when the target is empty. It also evaluates the error message.

   TEST_FIXTURE(CClientAuthDataFixture,
                InitializeWithEmptyStringAndCheckErrorMessage)
   {
      bool bReturn = testData.Initialize(m_sTarget);
      CHECK(bReturn == false);
      
      CTTString sErrorMsg = testData.GetLastError();      
      CHECK(sErrorMsg.Compare("A service target must be given in order 
to use Single Sign-On.") == 0);      
   }   

Example 2: Initialization test

Example: Invalid values

I wrote a test to ensure the system returns an error string when the target contained an invalid value. I wanted to make absolutely sure the expected failure was failing for the right reason. Notice that the code sends the error message to the console.

   TEST_FIXTURE(CClientAuthDataFixture, InitializeWithInvalidTarget)
   {
      m_sTarget = "invalid/invalid";
      bool bReturn = testData.Initialize(m_sTarget);
      CHECK(bReturn == false);
      
      CTTString sErrorMsg = testData.GetLastError();
      CHECK(!sErrorMsg.IsEmpty());      
      
      // This could be many different things. 
      // Print it out for visual inspection.
      std::cout << "Error message to verify: " 
                << sErrorMsg.GetStringPtr() 
                << std::endl << std::endl;      
   }   

Example 3: Invalid values

The output sent to the console shows that Kerberos could not resolve the target. The test was indeed valid.

Error message to verify: Unable to initialize security context. 
GSSAPI major error[131072]: An invalid name was supplied  minor 
error[-1765328168]: Hostname cannot be canonicalized

Example 4: Checking an error from the external system

This is an example of how not executing every test after every compile is beneficial. Ugly error messages from an external system are tough to test. The error could be different based on the configuration, or it could change when the system is upgraded to a newer version.

Example: Successful authentication

The final example tests for a successful authentication. It has the target variable properly initialized with a host of testad.wysicorp.com.

   TEST_FIXTURE(CClientAuthDataFixture, InitializeWithValidTarget)
   {
      m_sTarget = "service1/testad.wysicorp.com";
      bool bReturn = testData.Initialize(m_sTarget);
      CHECK(bReturn == true);
      
      CTTString sErrorMsg = testData.GetLastError();   
      CHECK(sErrorMsg.IsEmpty());       
      
      if (!sErrorMsg.IsEmpty())
      {
         std::cout << "Error message:"  
                   << sErrorMsg.GetStringPtr() 
                   << std::endl; 
      }     
   }

Example 5: Successful authentication

Again, the example shows how this kind of unit testing is valuable locally for design purposes. However, you can also see how fragile it would be to run it every single time against an external system that is out of your control.

TDD results: Only one bug

The most telling statistic for this project was the final bug count. When the QA department tested the application, they found a grand total of one defect. That bug was an obscure Kerberos interaction bug between very specific versions of Mac OS X and Active Directory.

Once the initial development was completed, I only had to run the unit tests against Active Directory at specific development milestones like the beginning of alpha or beta testing. The quality remained high, but I eliminated the hassle of setting up the Kerberos information every time.

In the end, by ignoring the TDD principle of running all tests every time, this project still achieved the most import goal of TDD: clean, high quality code.

-----------------------------------------
About the author: Grant Lammi is a technology strategist at Seapine Software who has over a decade of experience as a developer in the software industry. You can follow his blog at http://blogs.seapine.com/grant.


Rate this Tip
To rate tips, you must be a member of SearchSoftwareQuality.com.
Register now to start rating these tips. Log in if you are already a member.


Submit a Tip




Digg This!    StumbleUpon Toolbar StumbleUpon    Bookmark with Delicious Del.icio.us    Add to Google


RELATED CONTENT
Software Testing
Software testing affected by pressure to release software
Be aware of SOA application security issues
Performance testing: Ensure your SOA applications perform
Use functional and regression testing to validate SOA solutions
Overcoming user acceptance testing difficulties
Software testing on an agile project: How to get started
Unit, integration testing first steps toward SOA quality
Regression test cases in safety-critical software
What to include in a performance test plan
Unit testing in the enterprise: Five common myths dispelled

Test-driven development (TDD)
Clean Code: A Handbook of Agile Software Craftsmanship, Chapter 1 -- What Is Clean Code?
Improved software design with test-driven development (TDD)
Test-driven development and the ethics of quality
Continuous integration meets application performance management
Can test-driven development drive developers to test?
Barriers remain for test-driven development
Better software through debugging and unit testing -- Unit testing, Extreme Programming and TDD
Better software through debugging and unit testing -- Other useful resources
Better software through debugging and unit testing
Unit testing critical for improving software quality

Software unit testing
How to develop a checklist for unit, integration and system testing
Making unit testing a priority
The Art of Debugging with GDB, DDD, and Eclipse -- Ch. 1
An approach to integration testing
Clean Code: A Handbook of Agile Software Craftsmanship, Chapter 1 -- What Is Clean Code?
Unit, integration testing first steps toward SOA quality
Functional testing: Unit testing, integration testing and beyond
Unit testing in the enterprise: Five common myths dispelled
Six functional tests to ensure software quality
Parasoft's Adam Kolawa: Software quality is a continuous process

RELATED GLOSSARY TERMS
Terms from Whatis.com − the technology online dictionary
continuous integration  (SearchSoftwareQuality.com)
JUnit  (SearchSoftwareQuality.com)
NUnit  (SearchSoftwareQuality.com)
test-driven development  (SearchSoftwareQuality.com)

RELATED RESOURCES
2020software.com, trial software downloads for accounting software, ERP software, CRM software and business software systems
Search Bitpipe.com for the latest white papers and business webcasts
Whatis.com, the online computer dictionary

DISCLAIMER: Our Tips Exchange is a forum for you to share technical advice and expertise with your peers and to learn from other enterprise IT professionals. TechTarget provides the infrastructure to facilitate this sharing of information. However, we cannot guarantee the accuracy or validity of the material submitted. You agree that your use of the Ask The Expert services and your reliance on any questions, answers, information or other materials received through this Web site is at your own risk.



Software Design & Testing - Project Management
About Us  |  Contact Us  |  For Advertisers  |  For Business Partners  |  Site Index  |  RSS
SEARCH 
TechTarget provides enterprise IT professionals with the information they need to perform their jobs - from developing strategy, to making cost-effective IT purchase decisions and managing their organizations' IT projects - with its network of technology-specific Web sites, events and magazines.

TechTarget Corporate Web Site  |  Media Kits  |  Site Map




All Rights Reserved, Copyright 2006 - 2009, TechTarget | Read our Privacy Policy
  TechTarget - The IT Media ROI Experts