我在使用相对路径让dotCover在Albacore exec
任务中工作时遇到了一些问题。
@xUnitRunnerPath = Pathname.new('../../Tools/xUnit/xunitcontrib-dotcover.2.0/xunit.runner.utility.dll').realpath
@myTestDll = 'C:\PathToProj\My.Project.Tests\bin\Release\My.project.Tests.dll'
@outputDir = 'C:\PathToTestResults\'
exec :testCoverage do |cmd|
cmd.command = "C:/BuildAgent/tools/dotCover/dotCover.exe"
cmd.parameters = [
"cover",
"/targetexecutable=$$#{@xUnitRunnerPath}$$",
"/targetarguments=$$#{@myTestDll}$$",
"/output=#{@outputDir}/My.Project.Tests.dll.dcvr"
]
end
dotCover
错误只是告诉我路径错误
Failed to convert relative paths to absolute in parameters for the 'cover'
command. The given path's format is not supported.
这并没有提供太多帮助,我也尝试过dotcover帮助保护,但没有提供很多关于出错的线索。
我已关注this post about rake and dotcover和this question。也许我在这里错过了相关的文档,但能够让这个工作真的很有帮助。
/AnalyseTargetArguments=false
答案 0 :(得分:3)
我要从你自己的答案中重新混合rakefile / tasks。您应该遵循一些Ruby / Rake惯例以吸引更广泛的受众。我对如何编写令人敬畏的rakefiles有一些看法。特别是......
Rake::Task[:unitTestWithCoverage].execute( testAssembly )
有很多原因导致您不想直接使用Rake invoke
或execute
。其中一个不调用依赖任务,一个只运行一次依赖任务......它变得愚蠢。应始终有一种方法来构建正确定义和依赖的任务。
exec :unitTestWithCoverage, [:testAssembly] do |cmd, testAssembly|
您可能有一个静态列表或通配符匹配的测试程序集列表。您应该能够在不使用参数的情况下构建具体任务。当用户可以使用命令行中的自定义输入调用它们时,我只使用参数化任务。
testAssemblyRealPath = Pathname.new(testAssembly).realpath
testAssemblyName = File.basename(testAssemblyRealPath)
我们将探索Rake FileList
来弄清楚如何创建自定义,懒惰,mapped文件名/路径/任意字符串列表!
我在第一个答案中犯了一个严重错误(我保留在底部,供参考)。我会解释那部分你的/我的教育出了什么问题!
以下是我的新建议。这对我来说应该是显而易见的,因为我在自己的构建中使用mspec测试运行器任务犯了同样的错误。
dotcover_path = 'path/to/dotcover.exe'
xunit_runner_path = 'path/to/xunitrunner.exe'
test_assemblies = FileList['path/to/output/**/*.test.dll']
coverage_results = "#{test_results_path}/coverage_results.dcvr"
task :cover_all => [ :tests_with_coverage, :publish_coverage_results ]
exec :tests_with_coverage do |cmd|
cmd.comand = dotcover_path
cmd.parameters = [
"cover",
"/AnalyseTargetArguments=False",
"/TargetExecutable=\"#{xunit_runner_path}\"",
"/TargetArguments=\"#{test_assemblies.join ','}\"",
"/Output=\"#{coverage_results}\""
]
end
task :publish_coverage_results => [ :tests_with_coverage ] do
import_data 'dotNetCoverage', 'dotCover', coverage_results
end
def import_data(type, tool, file)
puts "##teamcity[importData type='#{type}' tool='#{tool}' path='#{file}']"
end
我默认使用绝对路径(通常使用File.expand_path
和__FILE__
常量)。有些工具/任务需要相对路径,但您始终可以使用File.basename
等方法。
dotcover_path = 'path/to/dotcover.exe'
xunit_runner_path = 'path/to/xunitrunner.exe'
我们仍然可以使用FileList
构建的程序集来定义目标程序集。在测试任务的主体执行之前,我们不会对其进行评估。
test_assemblies = FileList['path/to/output/**/*.test.dll']
coverage运行器支持具有单个结果文件的多个程序集。这样我们就没有另一个复杂的pathmap
。
coverage_results = "#{test_results_path}/coverage_results.dcvr"
从CI服务器调用此命令以运行测试并发布覆盖结果。
task :cover_all => [ :tests_with_coverage, :publish_coverage_results ]
此任务现在简单明了。一些说明:
1.使用join
将目标列表转换为正确格式的字符串。
2.我倾向于引用具有文件路径的exec任务参数(需要转义,\"
)。
exec :tests_with_coverage do |cmd|
cmd.command = dotcover_path
cmd.parameters = [
"cover",
"/AnalyseTargetArguments=False",
"/TargetExecutable=\"#{xunit_runner_path}\"",
"/TargetArguments=\"#{test_assemblies.join ','}\"",
"/Output=\"#{coverage_results}\""
]
end
相同的旧发布任务/方法。
task publish_coverage_results => [ :tests_with_coverage ] do
import_data 'dotNetCoverage', 'dotCover', coverage_results
end
def import_data(type, tool, file)
puts "##teamcity[importData type='#{type}' tool='#{tool}' path='#{file}']"
end
剪切以显示问题区域,假设其余部分无趣或存在于新解决方案中。
在之后构建任务之前,测试程序集将不存在。这通常不是问题,因为FileList
是懒惰的。在您对其进行枚举之前,它不会进行评估(例如,使用each
,map
或zip
)。
但是,我们立即each
来生成测试任务...所以这不起作用。它在列表中没有任何内容,也不会产生任何任务。或者,更糟糕的是,它会拾取前一个版本的输出,并可能做坏事(如果你没有完全清理输出目录)。
test_assemblies = FileList['path/to/output/**/*.test.dll']
coverage_results = test_assemblies.pathmap "#{test_results_path}/%n.dcvr"
cover_task_names = test_assemblies.pathmap "cover_%n"
test_assemblies.zip(coverage_results, cover_task_names) do |assembly, results, task_name|
exec task_name do |cmd|
cmd.command = dotcover_path
cmd.parameters = [
"cover",
"/AnalyseTargetArguments=False",
"/TargetExecutable=#{xunit_path}",
"/TargetArguments=#{assembly}",
"/Output=#{results}"
]
end
end
答案 1 :(得分:1)
对于任何对此感兴趣的人来说,我的最终佣金工作是
task :unitTestsWithCoverageReport => [ :unitTestsWithCoverage, :coverageServiceMessage ]
exec :unitTestsWithCoverage do |cmd|
fullPathAssemblies = []
@unitTestAssemblies.each do |testAssembly|
testAssemblyRealPath = Pathname.new(testAssembly).realpath
fullPathAssemblies << testAssemblyRealPath
end
cmd.command = @dotCoverRealPath
cmd.parameters = [
"cover",
"/AnalyseTargetArguments=False",
"/TargetExecutable=#{@xUnitRunnerRealPath}",
"/TargetArguments=\"#{fullPathAssemblies.join ';'}\"",
"/Output=#{@testResultsRealPath}/coverage.dcvr"
]
end
task :coverageServiceMessage do |t|
puts "##teamcity[importData type='dotNetCoverage' tool='dotcover' path='#{@testResultsRealPath}/coverage.dcvr']"
end
非常感谢@AnthonyMastrean,因为他向我展示了一些非常好的小红宝石技巧,以及我应该如何正确构建我的rake文件。