Click here to Skip to main content
15,880,392 members
Articles / Programming Languages / C#
Article

Simple Code Path Testing

Rate me:
Please Sign up or sign in to vote.
4.16/5 (10 votes)
8 Mar 20053 min read 67.1K   358   29   9
Add code path testing to your unit tests.

Introduction

I'm working on a core engine (something that is completely divorced from the Windows.System.Forms namespace but offers extensibility) for MyXaml, and the property setter is a complex beast with lots of different code paths. Besides wanting to make sure that all the code paths are tested, I also want to find out what code paths are never executed, usually due to too many patches and fixes applied, resulting in some brain dead code.

So, I got to thinking, how would I test my code paths? Something simple that doesn't require parsing out the IL or other highly complex techniques. Then I thought, why not use a custom Trace listener, put a specific Trace.Write() statement at the start of each path, and have the unit test engine tell me what code paths didn't execute after running all the tests in the fixture.

So, that's what I did, using my Advanced Unit Test tool. It's a simple solution, requires only a little overhead on the programmer's part to put in the Trace.Write statements, and results in useful information.

Using A Trace Listener

Instead of using a specific string format, I chose to pass a CodePath instance in the Trace.Write(object) method. It's easy to test if the object is a CodePath instance, and by using a class, it can be extended for some yet unknown future functionality. To make life simple, each code path is designated with a unique number. At the start of a method or a branch, simply add something like:

C#
Trace.Write(new CodePath(1));

Each method or branch gets a unique value. This isn't great, as you can accidentally use the same number, but in practice I've found that using a section, like "100-199" for a particular method, helps to keep things organized.

The trace listener implementation is straightforward:

public class CodePathListener : DefaultTraceListener
{
  protected Hashtable codePathTracker;

  public CodePathListener(Hashtable codePathTracker)
  {
    this.codePathTracker=codePathTracker;
  }

  public override void Write(object obj)
  {
    CodePath cp=obj as CodePath;
    if (cp != null)
    {
      if (codePathTracker.Contains(cp.PathNum))
      {
        int n=(int)codePathTracker[cp.PathNum];
        ++n;
        codePathTracker[cp.PathNum]=n;
      }
      else
      {
        codePathTracker[cp.PathNum]=1;
      }
    }
    else
    {
      base.Write(obj);
    }
  }
}

Using a HashTable, where the code path ID is the key, I can also count how many times the code path has executed for the tests in the fixture. However, this information isn't reported in the AUT GUI at this point.

New Attributes In AUT

There are three new attributes in AUT. Two of them can be applied to the test fixture itself:

  • CodePathRange
    C#
    [TestFixture]
    [CodePathRange(1, 6)]
    public class ...

    and

  • CodePaths
    C#
    [TestFixture]
    [CodePaths(1, 3, 6)]
    public class ...

    The meaning should be obvious--CodePathRange lets you specify an inclusive range of code path IDs that should be encountered by the tests in the fixture, while CodePaths lets you specify individual paths. More sophisticated parsing, like "1-5, 8, 9, 10-19" would be cool, but not implemented.

    A third attribute can be applied directly to the test:

  • ShouldExecuteCodePath
    C#
    [Test, ShouldExecuteCodePath(6)]
    public void ...

After the test runs, AUT checks to see, if the test encountered the code path of the supplied ID. The test fails if the code path was not encountered. Only one code path can be tested here, so this would usually be the terminal branch of a method.

Conclusion

That's it! I think it's quite simple but very useful. The download includes a code path test example and the current version of AUT.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions

 
GeneralInteger Expression Pin
Brigl13-Mar-06 6:08
Brigl13-Mar-06 6:08 
GeneralCode Coverage Pin
Johan Skrman16-Mar-05 21:59
Johan Skrman16-Mar-05 21:59 
GeneralNCover Pin
Daniel Turini10-Mar-05 6:02
Daniel Turini10-Mar-05 6:02 
GeneralCode Coverage Pin
jmw9-Mar-05 6:18
jmw9-Mar-05 6:18 
I think you'll find this is called code coverage testing... and you could use nCover to achieve what you're doing here without any code changes...
GeneralRe: Code Coverage Pin
Marc Clifton9-Mar-05 8:24
mvaMarc Clifton9-Mar-05 8:24 
GeneralRe: Code Coverage Pin
jmw9-Mar-05 8:27
jmw9-Mar-05 8:27 
GeneralRe: Code Coverage Pin
Marc Clifton9-Mar-05 8:37
mvaMarc Clifton9-Mar-05 8:37 
GeneralRe: Code Coverage Pin
jmw9-Mar-05 8:49
jmw9-Mar-05 8:49 
GeneralRe: Code Coverage Pin
dchrno9-Mar-05 9:18
dchrno9-Mar-05 9:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.