4

我在让 dotCoverexec使用相对路径在 Albacore 任务中工作时遇到了一些问题。

@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 help cover 以获得帮助,但没有提供很多关于出了什么问题的线索。

我已经关注了这篇关于 rake 和 dotcover 的帖子以及这个问题。也许我在这里错过了相关文档,但能够让它工作真的很有帮助。


编辑:我刚刚发现这与相对路径和绝对路径有关,也许是因为我使用的是绝对路径,所以我需要以下内容。我们明天就会知道

/AnalyseTargetArguments=false
4

2 回答 2

3

我将从您自己的答案中重新混合 rakefile/tasks。您应该遵循一些 Ruby/Rake 约定以吸引更广泛的受众。我对如何编写很棒的 rakefile 有一些看法。尤其...

1. 不要直接调用/执行 Rake 任务

Rake::Task[:unitTestWithCoverage].execute( testAssembly )

您不想直接使用 Rakeinvokeexecute. 其中一个不调用依赖任务,一个只运行一次依赖任务......它变得愚蠢。应该总是有一种方法来构建正确定义和依赖的任务。

2.不要参数化“内部”任务

exec :unitTestWithCoverage, [:testAssembly] do |cmd, testAssembly|

您可能有一个静态列表或通配符匹配的测试程序集列表。您应该能够在不使用参数的情况下构建具体任务。当用户可以从命令行使用自定义输入调用参数化任务时,我只使用参数化任务。

3. 无需在每个任务内创建路径

testAssemblyRealPath = Pathname.new(testAssembly).realpath
testAssemblyName = File.basename(testAssemblyRealPath)

我们将探索 RakeFileList以找出如何创建自定义、惰性、映射的文件名/路径/任意字符串列表!

混音(更新)

我在第一个答案中犯了一个严重错误(我将其保留在底部,以供参考)。我将解释您/我的教育在该部分中出了什么问题!

接下来是我的新建议。这对我来说应该很明显,因为我在自己的构建中使用 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']

覆盖运行程序支持具有单个结果文件的多个程序集。这样我们就没有另一个复杂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它很懒惰。在您枚举它之前,它不会评估(例如,使用eachmapzip)。

但是,我们立即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
于 2013-03-21T05:00:09.040 回答
1

对于任何对此感兴趣的人,这是我最后的 rake 任务

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,他向我展示了一些非常棒的 ruby​​ 小技巧以及我应该如何正确构建我的 rake 文件。

于 2013-03-19T13:10:36.090 回答