Tip: Limit coverage analysis when using NAnt, NCover

By erik at February 23, 2010 23:19
Filed Under: .NET, Software Development

I was having some difficulty the other day getting code coverage analysis to run on just the selected assemblies that I wanted in my build output directory, and had the requirement (placed on myself) that I didn’t want to list the assemblies declaratively in my build configuration file.  Not finding a quick solution, I thought I’d share what I came up with – it may end up being helpful to someone out there.  Please do let me know if you have another solution, I’d be interested in hearing about it.

As a background, I’m using the Gallio suite (including MbUnit) for testing which includes the Gallio test runner and custom Gallio NAnt task.  I want to limit the list of covered assemblies to those meeting a set of criteria, not all assemblies in a given folder.  The solution I came up with involves writing a custom NAnt function, which turns out to be a trivial thing to do.

First, a portion of my Gallio NAnt task:

    <gallio runner-type="NCover" 
            working-directory="${build.output.dir}"
            report-types="html"
            report-directory="${test.output.dir}"
            show-reports="false"
            failonerror="true"
            verbosity="Normal"
            echo-results="true">
      <runner-property value="NCoverArguments='//q //a ${coverage.assemblies}'"/>

Note the <runner-property /> element with NCoverArguments specified in the value attribute.  In this attribute, I specify a list of NCover runtime arguments, including the //a argument used to specify the list of assemblies to be profiled delimited by semi-colons.  The trick for me was to set this list dynamically.  I also, quite frankly, didn’t want to get into writing a ton of NAnt code using things like string::concat functions and whatnot.  Before I call this <gallio /> task in the appropriate target, I set a property like so:

    <property name="coverage.assemblies" 
              value="${mlincek::getcoverageassemblies(assembly.output.dir)}"/>

Essentially, here, I have set the list of coverage assemblies (property/variable ‘coverage.assemblies’) by calling out to a custom-written NAnt function that I have written, and passing in my build output directory as a string.  Note this function returns a string:

  <!-- Custom NAnt functions -->
  <script language="C#" prefix="mlincek">
    <code>
      <![CDATA[
        [Function("getcoverageassemblies")]
        public static string GetCoverageAssemblies(string assemblyFolder)
        {
          StringBuilder sb = new StringBuilder();
          FileInfo[] files = (new DirectoryInfo(assemblyFolder)).GetFiles();
          foreach (FileInfo file in files)
          {
            string fileName = file.Name;
            if (!fileName.EndsWith(".Tests.dll") && !fileName.EndsWith(".pdb"))
            {
              int dllPosition = fileName.LastIndexOf(".dll");
              sb.Append(fileName.Substring(0, dllPosition) + ";");
            }
          }
          return sb.ToString();
        }
      ]]>
    </code>
  </script>

You can place this script task at the bottom of your NAnt .build file, or do as I do and place it into a common.build file which you can reference via a NAnt <include /> task.  Of course, this function could be made more flexible and used for other things besides setting the coverage assembly list simply by passing in the filter criteria either as a string parameter, an expression, or a collection of rules (rule objects), but hey, this is a build file for gosh sakes and it got the job done for me.

Now, I can add assemblies to my overall solution and as long as I follow my naming conventions for projects and build folder structure, they will be picked up automatically for coverage analysis, per my filter criteria.

Hope this helps someone!

Add comment




  Country flag

biuquote
Loading



Visitors

Disclaimer

Views expressed are my own and in no way represent those of my employer; this is in no way a work or work-related blog.  All postings are presented "AS IS" and confer no rights.

Copyright

All content copyright © 2009-2011 by Erik Mlincek.  You may not use content without the express written consent of the author, however you may link back to blog topics hosted at mlincek.com without obtaining permission in advance.