David Walker

Debugging Visual Studio 2013 Code Coverage with ILSpy

by David Walker

So I am working on getting 100% code coverage for my tests on fFastMapper (My tool to do high-speed, precompiled mapping between 2 objects).  The following method is a single line and was being called in my tests.  However, Visual Studio 2013's code coverage tool was reporting that there was a block of code left untested.  I couldn't see any way this was possible.

public static TReturn Map<TLeft, TReturn>(this fFastMapperFluent<TLeft, TReturn> fluent, TLeft source)
     where TReturn : new()
{
     return fFastMapperInternal<TLeft, TReturn>.mapperFunc(source, new TReturn());
}

So I dragged out ILSpy thinking that I would have to slog through the IL (intermediate language that C# compiles to) to figure this one out.  I do this sometimes and find it educational but I don't do it enough that it comes natural.  As it turns out, I didn't need to go that far because the decompiled C# version of the method gave me my answer.

public static TReturn Map<TLeft, TReturn>(this fFastMapperFluent<TLeft, TReturn> fluent, TLeft source) where TReturn : new()
{
     return fFastMapperInternal<TLeft, TReturn>.mapperFunc(source, (default(TReturn) == null) ? Activator.CreateInstance<TReturn>() : default(TReturn));
}

Because my generic method supported being called by both value types and reference types, the compiler turns "new TReturn()" into 2 calls.  If the type is a value type, the code just returns the default of that type, but if it is a value type, it calls Activate.CreateInstance<TReturn> to create the new instance.

One solution to get code coverage for this code would have been to write another test that called this code with a value type.  However, this code wasn't actually intended to be used with value types so I fixed this by adding the generic constraint of "class".

public static TReturn Map<TLeft, TReturn>(this fFastMapperFluent<TLeft, TReturn> fluent, TLeft source)
     where TReturn : class,new()
{
     return fFastMapperInternal<TLeft, TReturn>.mapperFunc(source, new TReturn());
}

Now the code compiles as intended and the code coverage tool shows that I have coverage of that method.

David Walker

David Walker is a Software Consultant, Photographer, and Digital Artist based out of Orlando, Florida, USA.

He believes in secure reliable software and productive happy teams.

More ...