在上篇介紹了OpenCover的基本運作概念和為什麼要使用OpenCover,在這篇將會實際把OpenCover整合到Build Script裡面。
sample 程式在 github devops-psake sample/chapter16
同步發表於我的部落格:http://blog.alantsai.net/2017/01/devopsSeries-opencover-intergreateBuild.html (部落格的格式會漂亮一些)
要把OpenCover整合進入Build script需要做幾個事情:
這個部分需要先用Nuget把Opencover加入(Install-Package Opencover),之後,在Build Script裡面會多增加一個property:
$openCoverExe = (Get-PackagePath $packageDirectoryPath "OpenCover") +
"\tools\OpenCover.Console.exe"
在上篇提到,其實opencover有一個profiler,這個profiler會執行Test Runner,然後profiler會監控test runner記錄執行測試的涵蓋率。
因此,變成不直接呼叫TestRunner了,而是透過OpenCover,因此建立一個helper方法會方便呼叫測試。
OpenCover其實有滿多的設定,下面會一個一個介紹:
target
這個是用來執行Test Runner的路徑
targetargs
這邊是指要傳入給target的參數
output
這邊指的是Opencover的涵蓋率結果要儲存的位置
register
一直有提到OpenCover有一個profiler,這個profiler其實是一個com的library,因此要使用的話需要註冊和給權限。這邊我們使用參數user指的是profiler的權限同等於 目前user,因此避免到時候換build server或者換環境會有環境設定問題
filter
還記得上篇提到關於filter用來決定那些Assembly要涵蓋進來那些要排除,這個就是這邊傳入。
excludebyattribute
上篇提到透過attribute方式設定那些要過濾
excludebyfile
上篇提到,透過檔名過濾的地方
skipautoprops
這個指的是 程式碼裡面用的Property (常說的getter和setter,例如:public string Name{get;set;}),因為一般沒有邏輯,所以加入這個參數表示那些不要進入涵蓋範圍
mergebyhash
這個指的是,同一個dll可能會被多次載入(不同test framework等),加入這個設定表示,不管載入幾次,只要hash一樣,永遠算1次
mergeoutput
還記得提到說有不同test framework如何整合結果在一起?只要有設定這個參數,加上所有的output path一致,就會把結果整合
hideskipped
上面雖然有提供一些過濾方式,但是最後報表還是會有包含,只是說那些被忽略而已。因此這個參數能夠把被忽略的不在報告顯示。如果要讓報告乾淨一些,就可以讓他們不顯示
returntargetcode
這個指的是,最後的exit code要用target的作為回傳,這樣如果執行test有失敗,才能夠看到
對於幾個參數有瞭解之後,在helper就增加了一個Run-TestWithOpenCover:
function Run-TestWithOpenCover {
[CmdletBinding()]
param([Parameter(Position=0,Mandatory=1)]$testRunnerExe,
[Parameter(Position=1,Mandatory=1)]$testRunnerArg,
[Parameter(Position=2,Mandatory=1)]$openCoverExe,
[Parameter(Position=3,Mandatory=1)]$openCoverResult,
[Parameter(Position=4,Mandatory=1)]$filter,
[Parameter(Position=5,Mandatory=1)]$excludeAttribute,
[Parameter(Position=6,Mandatory=1)]$excludeFiles)
Exec { &$openCoverExe "-target:$testRunnerExe" `
"-targetargs:$testRunnerArg" `
"-output:$openCoverResult" `
-register:user `
"-filter:$filter" `
-excludebyattribute:$excludeAttribute `
-excludebyfile:$excludeFiles `
-skipautoprops `
-mergebyhash `
-mergeoutput `
-hideskipped:All `
-returntargetcode}
}
在上有些參數有用雙引號包住,例如"-targetargs:$testRunnerArg"
,這個原因是在Powershell如果參數有空白,要連參數名一起用雙引號包住。
Helper準備好了之後,在default.ps1要準備好幾個會傳入的參數,最主要是filter的參數的部分。所以,和其他參數一樣,現在Property裡面定義:
$openCoverResult = "$buildTestCoverageDirectory\openCover.xml"
$openCoverFilter = "+[*]* -[xunit.*]* -[*.NunitTest]* -[*.Tests]* -[*.XunitTest]*"
$openCoverExcludeAttribute = "System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute"
$openCoverExcludeFie = "*\*Designer.cs;*\*.g.cs;*\*.g.i.cs"
這些參數的用意透過剛剛介紹的參數作用應該很清楚,這邊就不做額外介紹。
在結束之前,還有一個地方要調整,就是BundleConfig.cs。
這邊將會用ExcludeFromCodeCoverageAttribute加入到他的Class裡面,用來把它排除在Coverage裡面
[ExcludeFromCodeCoverage]
public class BundleConfig
{
....
最後,就是調整3個測試的執行方式。做法都一樣,把本來呼叫exec改成呼叫在第二步建立的helper,有差別的地方都是在testRunnerExe和testRunnerArg
首先是Xunit:
$xmlResult = "$xunitTestResultDirectory\xUnit.xml"
$htmlResult = "$xunitTestResultDirectory\xUnit.html"
$targetArg = "$testAssembly -xml $xmlResult -html $htmlResult -nologo -noshadow"
Run-TestWithOpenCover -testRunnerExe $xunitExe `
-testRunnerArg $targetArg `
-openCoverExe $openCoverExe `
-openCoverResult $openCoverResult `
-filter $openCoverFilter `
-excludeAttribute $openCoverExcludeAttribute `
-excludeFiles $openCoverExcludeFie `
再來是NUnit:
$targetArg = "$testAssembly --result=$nunitTestResultDirectory\nUnit.xml"
Run-TestWithOpenCover -testRunnerExe $nunitExe `
-testRunnerArg $targetArg `
-openCoverExe $openCoverExe `
-openCoverResult $openCoverResult `
-filter $openCoverFilter `
-excludeAttribute $openCoverExcludeAttribute `
-excludeFiles $openCoverExcludeFie `
最後是MSTest:
$targetArg = "$testAssembly /Logger:trx"
Run-TestWithOpenCover -testRunnerExe $msTestExe `
-testRunnerArg $targetArg `
-openCoverExe $openCoverExe `
-openCoverResult $openCoverResult `
-filter $openCoverFilter `
-excludeAttribute $openCoverExcludeAttribute `
-excludeFiles $openCoverExcludeFie `
以上都做完之後,就可以執行做測試,並且會看到Coverage分數:
在這篇調整了build script,讓opencover進入並且產生出了測試涵蓋率的結果。
但是,這個結果畢竟比較偏summary,看不出到底那些沒cover到,所以在下篇將會進一步去看OpenCover所產生的結果xml,和如何把它轉換成人看得懂的格式