2017年1月2日 星期一

[iThome第8屆鐵人賽 16]OpenCover 整合篇

在上篇介紹了OpenCover的基本運作概念和為什麼要使用OpenCover,在這篇將會實際把OpenCover整合到Build Script裡面。

準備Build Script

要把OpenCover整合進入Build script需要做幾個事情:

  1. 把OpenCover加入到Build專案
  2. 建立一個Helper用來執行OpenCover
  3. 準備好執行Helper的參數
  4. 調整測試呼叫方式

把OpenCover加入到Build專案

這個部分需要先用Nuget把Opencover加入(Install-Package Opencover),之後,在Build Script裡面會多增加一個property

$openCoverExe = (Get-PackagePath $packageDirectoryPath "OpenCover") +
		"\tools\OpenCover.Console.exe"

建立一個Helper用來執行OpenCover

在上篇提到,其實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的參數

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,有差別的地方都是在testRunnerExetestRunnerArg

首先是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分數:

image
看到結果分數

結語

在這篇調整了build script,讓opencover進入並且產生出了測試涵蓋率的結果。

但是,這個結果畢竟比較偏summary,看不出到底那些沒cover到,所以在下篇將會進一步去看OpenCover所產生的結果xml,和如何把它轉換成人看得懂的格式


沒有留言 :

張貼留言