我们使用NUnit-NCover完成了这个任务,并对结果感到非常满意。
我们在NUnit执行后执行
NUnitTfs来发布测试结果。然后,NCover启动并生成我们的代码覆盖率结果。
一个主要的缺点是设置正确调用NCover的参数不是很容易。但是自从我安装它以来,我就再也没有维护过它了。
有两件事可能会带来不便:
- NUnitTfs与NCover不兼容(至少我找不到一种同时执行两者的方法,因此(由于NCover调用NUnit),我必须运行两次单元测试:(1)获得测试结果和(2)通过NCover获得覆盖率结果。这自然使我的构建时间更长。
- 设置正确调用NCover的参数不是很容易。但是自从我安装它以来,我就再也没有维护过它。
无论如何,最终的报告(特别是趋势方面)对于监控我们的代码在时间内如何演变非常有用。特别是如果您正在处理平台(而不是短期项目),趋势报告具有巨大价值。
编辑
我将尝试以简单明了的方式展示如何实现此目标,希望它有用。我们的构建服务器上当前安装了NCover 3.4.12。
我们的NUnit程序集的简单命名约定是,如果我们有一个生产程序集“123.dll”,则存在另一个名为“123_nunit.dll”的程序集来实现其测试。因此,每个构建都有几个*_nunit.dll程序集是有意义的。
在“如果未禁用测试”下的构建过程模板部分已经进行了重新设计,以实现我们的目标,特别是被命名为“运行Test Assemblies的MSTest”的部分。整个实现在这里,经过一些清理以使流程更易于理解(图片太大无法直接插入此处)。
首先,在构建过程模板中实现了一些额外的参数,并且然后可以在每个构建定义中设置:
然后我们在“Formulate nunitCommandLine”中形成NUnit args:
String.Format("{0} /xml={1}\\{2}.xml", nunitDLL, TestResultsDirectory, Path.GetFileNameWithoutExtension(nunitDLL))
这之后会在“Invoke NUnit”中使用。
如果执行成功且我们已经为此构建设置了覆盖率,我们将转向“Generate NCover NCCOV”(此特定程序集的覆盖文件)。为此,我们调用NCover.Console.exe,并使用以下参数:
String.Format("""{0}"" ""{1}"" //w ""{2}"" //x ""{3}\{4}"" //literal //ias {5} //onlywithsource //p ""{6}""",
NUnitPath,
Path.GetFileName(nunitDLL),
Path.GetDirectoryName(nunitDLL),
Path.GetDirectoryName(Path.GetDirectoryName(nunitDLL)),
Path.GetFileName(nunitDLL).Replace("_nunit.dll", ".nccov"),
Path.GetFileNameWithoutExtension(nunitDLL).Replace("_nunit", ""),
BuildDetail.BuildNumber)
所有这些都在foreach循环“对于所有nunit dlls”中运行。当我们退出循环时,我们进入“最终NCover活动”,首先是“合并NCCovs”部分,在此部分中再次执行NCover.Console.exe-这次使用不同的参数:
String.Format("""{0}\*.nccov"" //s ""{0}\{1}.nccov"" //at ""{2}\{3}\{3}.trend"" //p {1} ",
Path.GetDirectoryName(Path.GetDirectoryName(testAssemblies(0))),
BuildDetail.BuildNumber,
NCoverDropLocation,
BuildDetail.BuildDefinition.TeamProject
)
当此过程运行结束时,我们已经达到了所有NCCOV文件合并为一个名为构建名称+NCCOV文件的点,并且该进程的Trend文件(监控整个构建过程)已经更新为包含当前构建元素的状态。现在我们只需生成最终的HTML报告,在“生成最终NCover rep”中调用NCover.reporting即可,使用以下参数:
String.Format(" ""{0}\{1}.nccov"" //or FullCoverageReport //op ""{2}\{1}_NCoverReport.html"" //p ""{1}"" //at ""{3}\{4}\{4}_{5}.trend"" ",
Path.GetDirectoryName(Path.GetDirectoryName(testAssemblies(0))),
BuildDetail.BuildNumber,
PathForNCoverResults,
NCoverDropLocation,
BuildDetail.BuildDefinition.TeamProject,
BuildType
)