首页 文章

使用dotCover命令行对IIS进行代码覆盖

提问于
浏览
2

由JetBrains集成到ReSharper Ultimate中的dotCover客户端工具包括一个获取在IIS下运行的应用程序(例如ASP.NET MVC应用程序)的代码覆盖率的选项 .

JetBrains的TeamCity持续集成系统包括一个集成在其中的免费命令行版本的dotCover . VSTest运行器可以很好地使用dotCover生成单元测试的代码覆盖率 . 但是,它不会生成在IIS下运行的代码的任何代码覆盖,例如使用Selenium WebDriver之类的集成测试 .

有没有办法在TeamCity中使用dotCover命令行工具来获取在IIS下运行的应用程序的代码覆盖率?

1 回答

  • 5

    使用dotCover命令行的IIS代码覆盖率尚未实现,如dotCover问题跟踪器上的this ticket所述 .

    但是,使用a comment by Tony Fabris on the ticket中的提示,我能够创建一个Powershell脚本,该脚本可以生成应用程序的代码覆盖率 . 这使用IIS Express而不是IIS,这不是理想的,但现在足够接近 .

    我已经在这里发布了我的脚本,以防它对其他人有用 .

    # This script runs our web-based tests, running IISExpress via TeamCity's 
    # dotCover, then runing the tests (also in dotCover) and then importing the 
    # test results and coverage results back into TeamCity.
    
    # Note that some of the following is based on the comments by Tony Fabris on
    # 20th Jan 2016 from here: https://youtrack.jetbrains.com/issue/DCVR-5921
    
    # Configuration.
    # The path to IIS Express.
    $IISExpressPath = "C:\Program Files (x86)\IIS Express\IISExpress.exe"
    # The path to dotCover, the TeamCity tool for .NET code coverage.
    $DotCoverPath = "C:\TeamCity\buildAgent\tools\dotCover\dotcover.exe"
    # The path to the VSTest console.
    $VSTestConsolePath = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"
    # The path to PSExec.
    $PSExecPath = "C:\path\to\PSTools\PSExec.exe"
    # The path of the website which will be hosted in IIS express.
    $WebsitePath = "C:\path\to\webapp"
    # The port on which to host the website.
    $WebsitePort = 12345
    # The path to use as the working directory when running the tests.
    # Note that the test results are written to a .trx file in a TestResults 
    # subdirectory of this directory.
    $TestWorkingPath = "c:\path\to\checkout\dir"
    # The assembly to run tests for.
    $TestAssembly = "C:\path\to\test.dll"
    
    # Get the TEMP folder.
    # When run from the command-line, this will be something like the user's AppData\Local\Temp 
    # When run from TeamCity, this will be something like C:\TeamCity\buildAgent\temp\buildTemp
    $tempDir = (Get-Item $Env:TEMP).FullName
    Write-Host ("tempDir: " + $tempDir)
    
    # Work out the output directory to write various output files to, in a 
    # CustomCoverage subdirectory of the temporary directory.
    $outputDir = Join-Path $tempDir "CustomCoverage"
    Write-Host ("outputDir: " + $outputDir)
    
    # Create that output directory, but only if it doesn't exist.
    if (!(Test-Path $outputDir))
    {
        md $outputDir
    }
    
    # Work out the path of the dotcover log file used for IISExpress, and delete it
    # if it already exists.
    $dotCoverIISExpressLogFilename = "$outputDir\dotcover.iisexpress.log.txt"
    If (Test-Path $dotCoverIISExpressLogFilename)
    {
        del $dotCoverIISExpressLogFilename
    }
    
    # Work out the path of the dotCover output file used for IISExpress.
    $dotCoverIISExpressOutputFilename = "$outputDir\dotcover.iisexpress.dcvr"
    
    # Work out the arguments that we'll pass to IIS Express.
    $IISExpressArgs = "/path:$WebsitePath /port:$WebsitePort /trace:info"
    
    # Work out the arguments to pass to dotCover to start and cover IIS Express.
    # Because the arguments to dotCover are long, we write them out to a config file.
    $dotCoverIISExpressConfigFilename = "$outputDir\dotcover.iisexpress.config.xml"
    "<?xml version=`"1.0`" encoding=`"us-ascii`"?>`n" + `
    "<CoverageParams>`n" + `
    "  <LogFile>$dotCoverIISExpressLogFilename</LogFile>`n" + `
    "  <Output>$dotCoverIISExpressOutputFilename</Output>`n" + `
    "  <TargetExecutable>$IISExpressPath</TargetExecutable>`n" + `
    "  <TargetArguments>$IISExpressArgs</TargetArguments>`n" + `
    "</CoverageParams>`n" `
    | Out-File -Encoding ASCII $dotCoverIISExpressConfigFilename
    
    # Write the command to execute dotCover out to a .bat file.
    # Within the batch file we redirect stdout and stderr to a file, so we can see
    # any reasons for failure.
    # We put this in a batch file because it is too long for PSExec, which is 
    # limited to 260 characters for a single argument.
    # http://forum.sysinternals.com/psexec-argument-to-long_topic14203.html
    $dotCoverIISExpressRunFilename = "$outputDir\dotcover.iisexpress.run.bat"
    "`"$DotCoverPath`" cover `"$dotCoverIISExpressConfigFilename`" > `"$outputDir\iisexpress.stdout.txt`" 2> `"$outputDir\iisexpress.stderr.txt`"" | Out-File -Encoding ASCII $dotCoverIISExpressRunFilename
    
    # We need to run IISExpress (hosted in dotCover) in an interactive session, in 
    # order to be able to send it a WM_QUIT to shut it down gracefully after the
    # tests (or else no coverage data will be recorded).
    # We do this by running dotCover via PSExec.
    # -i : interactive session
    # -h : use the account's elevated token
    # -accepteula : accept the pstools EULA, as the user running the build agent probably won't have
    $psExecArgs = "-i -h -accepteula `"$dotCoverIISExpressRunFilename`""
    
    # Start PSExec -> DotCover -> IISExpress.
    # This will block, so we use Start-Process so that's it's done in a separate
    # process, and so this script will continue.
    # The -PassThru argument is required so that Start-Process will return a process
    # handle.
    $IISExpressProcess = (Start-Process $PSExecPath $psExecArgs -PassThru)
    
    # Work out the path of the dotcover log file used for VSTest, and delete it
    # if it already exists.
    $dotCoverVSTestLogFilename = "$outputDir\dotcover.vstest.log.txt"
    If (Test-Path $dotCoverVSTestLogFilename)
    {
        del $dotCoverVSTestLogFilename
    }
    
    # Work out the path of the dotCover output file used for VSTest.
    $dotCoverVSTestOutputFilename = "$outputDir\dotcover.vstest.dcvr"
    
    # Work out the arguments to pass to VSTest console.
    # The /Logger:trx argument outputs the results in MSTest format, which TeamCity
    # is able to import.
    $vsTestArgs = "`"$TestAssembly`" /Logger:trx"
    # Then run dotCover to run VSTest.
    # This will run the tests, and also collect code coverage for the tests 
    # themselves.
    # We expect the tests to be making calls to the website, which is running on IIS
    # Express and being covered that way.
    & $DotCoverPath cover /LogFile="$dotCoverVSTestLogFilename" /Output="$dotCoverVSTestOutputFilename" /TargetExecutable="$VSTestConsolePath" /WorkingDir="$TestWorkingPath" /TargetArguments="$vsTestArgs"
    
    # We now need to shut down IISExpress.
    # This has to be done gracefully, or else coverage data won't be collected.
    # The core command to do this is 'taskkill /IM IISExpress.exe'.
    # Note that there's no /F parameter to force - so what this will do is send a
    # WM_QUIT to the process, to tell it to shut down.
    # However, this only works if IISExpress was run in an interactive session (-i),
    # and also if this taskkill call is as well.
    # Both also require the -h parameter (elevated token) to be able to work.
    
    # Note that we also want to log the output of taskkill, to help track down any
    # issues.
    # If we just do this, then powershell handles the redirection to the file:
    # & PSExec taskkill > output.txt
    # If we add a ` to escape the >, then powershell doesn't do the redirection, but
    # we still end up redirecting the output of PSExec, instead of the output of
    # taskkill.
    # & PSExec taskkill `> output.txt
    # Using 'cmd /C' instead allows us to pass the command in quotes, and therefore
    # the redirect applies to the taskkill, instead of to the PSExec:
    # & PSExec cmd / C "taskkill `> output.txt"
    # We log the output of stdout (via >) and stderr (via 2>).
    
    # So stop IIS Express.
    & $PSExecPath -i -h -accepteula cmd /C `"taskkill /IM IISExpress.exe `> "$outputDir\taskkill.stdout.txt" 2`> "$outputDir\taskkill.stderr.txt"`"
    
    # As a record, write out the contents of the stdout and stderr log files, for 
    # both IIS Express and taskkill, to help track down any issues.
    # Note that IIS Express will have been logging during execution of the tests, so
    # we can't collect the log until we've killed it.
    Write-Host "-- iis express stdout --"
    Get-Content "$outputDir\iisexpress.stdout.txt"
    Write-Host "------------------------"
    Write-Host "-- iis express stderr --"
    Get-Content "$outputDir\iisexpress.stderr.txt"
    Write-Host "------------------------"
    Write-Host "-- taskkill stdout -----"
    Get-Content "$outputDir\taskkill.stdout.txt"
    Write-Host "------------------------"
    Write-Host "-- taskkill stderr -----"
    Get-Content "$outputDir\taskkill.stderr.txt"
    Write-Host "------------------------"
    
    # IIS Express takes a little while to close, the dotCover which is wrapping it
    # then takes a little while to write out the results. This is all wrapped up in
    # PSExec. Wait for this chain of processes to exit.
    Write-Host "Waiting for IIS Express to close..."
    $IISExpressProcess.WaitForExit()
    Write-Host "- done"
    
    # Import the test results in the .trx file in MSTest format.
    # Note that this path is relative to the checkout directory, and that VSTest
    # writes the output into the TestResults subdirectory of the working directory 
    # it was invoked with.
    Write-Host "##teamcity[importData type='mstest' path='TestResults\*.trx']"
    
    # These commands create an XML report from the dotCover coverage files.
    # This isn't necessary, as TeamCity will handle merging the coverage files and
    # then generating the report.
    # However it may be useful to uncomment these for testing.
    #& $DotCoverPath report /Source:$dotCoverIISExpressOutputFilename /Output:$outputDir\dotcover.iisexpress.report.xml /ReportType:xml
    #& $DotCoverPath report /Source:$dotCoverVSTestOutputFilename /Output:$outputDir\dotcover.vstest.report.xml /ReportType:xml
    
    # Write a service message to make TeamCity import code coverage from IIS express.
    # Note that TeamCity will delete this file once it has processed it.
    Write-Host "##teamcity[importData type='dotNetCoverage' tool='dotcover' path='$dotCoverIISExpressOutputFilename']"
    
    # Write a service message to make TeamCity import code coverage from VSTest.Console.
    # Note that TeamCity will delete this file once it has processed it.
    Write-Host "##teamcity[importData type='dotNetCoverage' tool='dotcover' path='$dotCoverVSTestOutputFilename']"
    

    请注意,在我的情况下,我结帐到固定目录,因此网站,工作路径和测试程序集都是已知的绝对路径 . TeamCity默认是为每个构建签出到不同的临时目录,因此如果您使用默认目录,则需要更改脚本以考虑该目录 .

相关问题