TestRunner for Visual Studio 2005 Manual

Using Code Coverage

TestRunner helps you improve the quality of your tests by computing code coverage automatically. Coverage results are summarized into a tool window as well as marked directly in the Visual Studio editor.

Setting Up

We'll make a simple class with a simple test case to illustrate driving your tests with coverage. For the first pass, we'll assume a simple method with and if statement that has one test already in place, but that hasen't managed to exercise the code fully. Create a new library project, and click Tools | TestRunner Coverage to activate the code coverage window. The code is:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;

namespace ClassLibrary3 {
    public class Class1 {
        public bool DoThings(bool mode) {
            if (mode) {
                System.Diagnostics.Trace.WriteLine("true");
            } else {
                System.Diagnostics.Trace.WriteLine("false");
            }
            return mode;
        }
    }

    [TestFixture]
    public class TestClass {
        [Test]
        public void TestOne(){
            Assert.IsTrue(new Class1().DoThings(true));
        }
    }
}        
        

Running the test we can see instantly that we aren't at full coverage in the tool window, or in the editor. In the tool window, you can use the Options menu to exclude test cases from coverage when you want to compute code coverage without including tests into the count. You can also filter by project with the the check boxes to calculate coverage only in specific assemblies, if for example you have tests in different assemblies or code that you aren't currently worried about.

The tool window gives an overview, while the editor gutter markers show specific lines that are hit or missed. You can use the Tools | Options to hide hit marks so that you can see only misses, or change the colors if red and green are too holiday festive for you.

Getting Covered

Well, it looks like we need another test to exercise the second code path, passing a false to run that else branch. Here is the code:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;

namespace ClassLibrary3 {
    public class Class1 {
        public bool DoThings(bool mode) {
            if (mode) {
                System.Diagnostics.Trace.WriteLine("true");
            } else {
                System.Diagnostics.Trace.WriteLine("false");
            }
            return mode;
        }
    }

    [TestFixture]
    public class TestClass {
        [Test]
        public void TestOne(){
            Assert.IsTrue(new Class1().DoThings(true));
        }
        [Test]
        public void TestTwo() {
            Assert.IsFalse(new Class1().DoThings(false));
        }
    }
}
        
        

Now that we have tests for both paths, we have 100% coverage.

Recap

Integrating code coverage into unit testing helps you figure out when you are really finished, and to see if you code has drifted away from your tests over time, when tiny changes can sneak in without a corresponding test. High coverage doesn't guarantee good tests, but less than 100% coverage is a sure sign that you have code that either isn't used, or when used isn't necessarily ready for the big time.