I've been working on adding an ncover report to my build system. My QA manager likes the idea of seeing the summary report of the modules, but does not need all the detail produced by ncover.
My solution has approximately 50 projects. When I submit all the dlls for nunit testing in one step, i.e. ncover-console /c nunit.console "A.dll B.dll ..." I get a good report, but... (1) The output coverage file is roughly 6 MB of xml (all on a single line) (2) The coverage file takes a long time to load (3) Manager only cares about the first of 150 some pages. On the other hand, I can run ncover 50 some times and get summaries of the individual assemblies, but then I don't get an overall summary for the whole solution. I ended up writing a custom task that someone might file useful, called ncoversummary. It takes multiple ncover reports, extracts out the coverage statistics, and writes the stats to another xml file. I'm an XML dummy, so I am not providing an transform to make the stats look pretty, but I (somehow) managed to write the XPATH statements to get the stats. You can use this as starting point for something better, or make use of it as is. I hope this survives the trip through Yahoo without getting too distorted. using System; using System.Collections; using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Xml; using System.Xml.XPath; using System.Text; using NAnt.Core; using NAnt.Core.Attributes; using NAnt.Core.Tasks; using NAnt.Core.Util; using NAnt.Core.Types; namespace NCoverSummary { /// <summary> /// Produces a summary of one or more Ncover output files /// </summary> [TaskName("ncoversummary")] public class NCoverSummaryTask : Task { #region Private Instance Fields private FileSet _fileset = new FileSet(); private FileInfo _tofile; #endregion Private Instance Fields #region Public Instance Properties /// <summary> /// All the files in the file set will be summarized. /// </summary> [BuildElement("fileset")] public FileSet SummaryFileSet { get { return _fileset; } set { _fileset = value; } } /// <summary> /// The name of the output file to write summary to /// </summary> [TaskAttribute("tofile")] public FileInfo ToFile { get {return _tofile;} set {_tofile = value;} } #endregion Public Instance Properties #region Override implementation of Task /// <summary> /// Checks whether all items are set /// </summary> /// <param name="taskNode">The <see cref="XmlNode" /> used to initialize the task.</param> protected override void InitializeTask(XmlNode taskNode) { if (ToFile == null || SummaryFileSet == null) { throw new BuildException(string.Format(CultureInfo.InvariantCulture,"Both 'tofile' and 'fileset' must be specified")); } } /// <summary> /// Overrides the task execute /// </summary> protected override void ExecuteTask() { if (SummaryFileSet.FileNames.Count > 0) { Log(Level.Info,"Summarizing {0} NCover Files",SummaryFileSet.FileNames.Count); } // open the output file XmlTextWriter textWriter = new XmlTextWriter(ToFile.FullName,null); textWriter.Formatting = Formatting.Indented; textWriter.WriteStartDocument(); try { // extract the information from the file foreach (string path in SummaryFileSet.FileNames) { SummarizeNCoverFile(path, textWriter); } } finally { textWriter.WriteEndDocument(); textWriter.Flush(); textWriter.Close(); } } #endregion #region private /// <summary> /// Extracts code coverage stats from a single ncover xml file /// </summary> /// <param name="path">path to ncover file</param> /// <param name="writer">xml output file object</param> private void SummarizeNCoverFile(String path, XmlTextWriter writer) { if (Verbose) { Log(Level.Verbose,"Checking ncover input file {0}",path); } // load the xml document XmlDocument document = new XmlDocument(); document.Load(path); // find number of modules described in this file XmlNodeList modules = document.SelectNodes("/coverage/module"); Log(Level.Verbose,"File {0} has {1} assembly modules", path, modules.Count); // loop over the number of modules foreach (XmlNode module in modules) { string moduleName = module.Attributes.GetNamedItem("name").Value; string assemblyName = module.Attributes.GetNamedItem("assembly").Value; XmlNodeList nodesTotal = module.SelectNodes("method/seqpnt"); XmlNodeList nodesWithZeroHits = module.SelectNodes("method/[EMAIL PROTECTED]'0']"); double coverage = ComputeCoverage(nodesTotal.Count,nodesWithZeroHits.Count); writer.WriteStartElement("module"); writer.WriteAttributeString("name",moduleName); writer.WriteAttributeString("assembly",assemblyName); writer.WriteAttributeString("totalines",nodesTotal.Count.ToString()); writer.WriteAttributeString("coverage",coverage.ToString()); writer.WriteEndElement(); } } /// <summary> /// Computes the amount of code coverage from the nodes /// </summary> /// <param name="totalNodes">total number of executed lines in code</param> /// <param name="nodesNotCovered">number of lines not executed during testing</param> private double ComputeCoverage (int totalNodes, int nodesNotCovered) { if (totalNodes > 0) return ((double)(totalNodes-nodesNotCovered)/totalNodes); else return 0.0; } #endregion } } ____________________________________________________ Start your day with Yahoo! - make it your home page http://www.yahoo.com/r/hs ------------------------------------------------------- SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click _______________________________________________ NAntContrib-Developer mailing list NAntContrib-Developer@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/nantcontrib-developer