[ExcludeFromCodeCoverage] — Oh, the Pain!

If you make use of Visual Studio’s built-in code coverage feature, you are probably aware of the existence of the ExcludeFromCodeCoverage attribute. This attribute, when decorating a piece of code, will exclude that code from all code coverage instrumentation. The end effect of its use is the total exclusion of the method or type from the code coverage report we all are treated with at the conclusion of the testing session.

While it does its job, its use is a bit intrusive, especially since all we are doing is appeasing a specific testing tool. It would be nice if there was some sort of coverage configuration file one could edit in order to exclude specific code elements, but no such thing exists in Visual Studio’s code coverage system. Perhaps the visibility of such things is a benefit, because it makes the fact that the code isn’t being counted in the coverage metric blatantly obvious. But it’s only obvious if you are actually looking at that code and not just a coverage report along with some top-level project files. Plus, the assumption is, is that you are a competent individual who wouldn’t be itching to exclude something from coverage analysis unless you had a good reason to do so.

With all that said, it’s my opinion the process of realizing code coverage exclusion through the use of the ExcludeFromCodeCoverage attribute is clumsy and not ideal. This gets further exacerbated when we want to go beyond the type-level and exclude an entire namespace from code coverage. That isn’t an option with the ExcludeFromCodeCoverage attribute; you are limited to types, methods, properties, indexers, and events.

Well there is a better way. Using PostSharp, we can devise our own scheme of coverage exclusion by creating a very simple aspect that will allow us to target entire namespaces if we wish, as well as smaller items in scope, all without having to touch any of the code being excluded.

The DisableCoverage Aspect

The aspect we’ll be designing here will act as a vehicle for the efficient delivery of our adored ExcludeFromCodeCoverage attribute to the intended pieces of code we wish to exclude. We will then make use of PostSharp’s multicasting feature in order to steer this vehicle.

The code for the aspect can be found, and, as you can see, it’s extremely simple:

[MulticastAttributeUsage(MulticastTargets.Class | MulticastTargets.Struct)]
public sealed class DisableCoverageAttribute : TypeLevelAspect, IAspectProvider
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        Type disabledType = (Type) targetElement;

        CustomAttributeIntroductionAspect introducedExclusion
            = new CustomAttributeIntroductionAspect(
                new ObjectConstruction(typeof (ExcludeFromCodeCoverageAttribute)));

        return new[] {new AspectInstance(disabledType, introducedExclusion)};

All this aspect does is introduce the ExcludeFromCodeCoverage attribute into all applied targets. I have the AttributeUsage of this attribute set to target only assemblies because using this aspect in any other way defeats its entire purpose. The MulticastAttributeUsage of this attribute, on the other hand, is targeting classes and structs. The reason I do this is so that the ExcludeFromCodeCoverage attributes we’re introducing are done so at the type-level, which is the most granular level of scope I wish to specify when using this aspect.

Let’s say you have a namespace named Bad.Tomato containing a bunch of classes you wish to exclude from coverage. To use our aspect in order to realize this wish, you would open up your project’s AssemblyInfo.cs file and add the following assembly-level attribute declaration:

[assembly: DisableCoverage(AttributeTargetTypes="Bad.Tomato.*")]

This will then result in the exclusion of all code elements belonging to the Bad.Tomato namespace from coverage analysis.

Maybe targeting a whole namespace is a bit too drastic for your tastes…maybe we only want to exclude a single class named Bad.Tomato.Farmer. Ok…then:

[assembly: DisableCoverage(AttributeTargetTypes="Bad.Tomato.Farmer")]

Hooray, no more ExcludeFromCodeCoverage! If you want to get even more granular, you can, and I believe you can make use of regular expressions here as well.

Matt Weber

I'm the founder of Bad Echo LLC, which offers consulting services to clients who need an expert in C#, WPF, Outlook, and other advanced .NET related areas. I enjoy well-designed code, independent thought, and the application of rationality in general. You can reach me at matt@badecho.com.

 Leave a Reply



You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2012-2013 Matt Weber. All Rights Reserved. Terms of Use.