2016-03-17 31 views
1

由JetBrains集成到ReSharper Ultimate中的dotCover客戶端工具包括一個用於獲取運行在IIS下的應用程序(例如ASP.NET MVC應用程序)的代碼覆蓋率的選項。使用dotCover命令行的IIS代碼覆蓋率

JetBrains的TeamCity持續集成系統包含一個集成到其中的免費命令行版本的dotCover。 VSTest亞軍使用dotCover爲單元測試生成代碼覆蓋率工作良好。但是,它不會產生任何在IIS下運行的代碼的代碼覆蓋率,例如使用Selenium WebDriver進行集成測試。

有沒有辦法在TeamCity中使用dotCover命令行工具來獲取在IIS下運行的應用程序的代碼覆蓋範圍? IIS與dotCover命令行

回答

3

代碼覆蓋率尚未實施,作爲對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的默認設置是爲每個構建簽出一個不同的臨時目錄,所以如果你使用默認的話,你需要改變腳本以考慮到這一點。