I’ve previously depended a little too much on TeamCity to construct our build process, but have been increasingly shifting everything to our build scripts (and therefore source control).
We’ve been using F# make – an awesome cross platform build automation tool like make & rake.
As an aside (before you ask): The dotCover support in TeamCity is already excellent – as you’d expect – but if you want to use these coverage files elsewhere (NDepend, say), then you can’t use the out-of-the-box options very easily.
Downloading your dependencies
We’re using NUnit and MSpec to run our tests, and so in order to run said tests, we need to ensure we have the test runners available. Rather than committing them to source control, we can use F# make’s support for restoring NuGet packages.
[code language=”fsharp”]
RestorePackageId (fun p -> { p with OutputPath = "tools"; ExcludeVersion = true; Version = Some (new Version("2.6.3")) }) "NUnit.Runners"
[/code]
DotCover is a little trickier, as there’s no NuGet package available (the command line exe is bundled with TeamCity). So, we use the following helper and create an F# make target called “EnsureDependencies” to download our dotCover and NDepend executables from a HTTP endpoint:
[code language=”fsharp”]let ensureToolIsDownloaded toolName downloadUrl =
if not (TestDir (toolsDir @@ toolName)) then
let downloadFileName = Path.GetFileName(downloadUrl)
trace ("Downloading " + downloadFileName + " from " + downloadUrl)
let webClient = new System.Net.WebClient()
webClient.DownloadFile(downloadUrl, toolsDir @@ downloadFileName)
Unzip (toolsDir @@ toolName) (toolsDir @@ downloadFileName)
Target "EnsureDependencies" (fun _ ->
ensureToolIsDownloaded "dotCover" "https://YourLocalDotCoverDownloadUrl/dotCoverConsoleRunner.2.6.608.466.zip"
<code>RestorePackageId (fun p -> { p with OutputPath = "tools"; ExcludeVersion = true; Version = Some (new Version("2.6.3")) }) "NUnit.Runners"
[/code]
Generating the coverage reports
Next up is creating a target to actually run our tests and generate the coverage reports. We’re using the DotCover extensions in F# Make that I contributed a little while back. As mentioned, we’re using NUnit and MSpec which adds a little more complexity – as we must generate each coverage file separately, and then combine them.
[code language=”fsharp”]Target "TestCoverage" (fun _ ->
let filters = "-:*.Tests;" # exclude test assemblies from coverage stats
# run NUnit tests via dotCover
!! testAssemblies
|> DotCoverNUnit (fun p -> { p with
Output = artifactsDir @@ "NUnitDotCover.snapshot"
Filters = filters }) nunitOptions
# run the MSpec tests via dotCover
!! testAssemblies
|> DotCoverMSpec (fun p -> { p with
Output = artifactsDir @@ "MSpecDotCover.snapshot"
Filters = filters }) mSpecOptions
# merge the code coverage files
DotCoverMerge (fun p -> { p with
Source = [artifactsDir @@ "NUnitDotCover.snapshot";artifactsDir @@ "MSpecDotCover.snapshot"]
Output = artifactsDir @@ "DotCover.snapshot" })
# generate a HTML report
# you could also generate other report types here (such as NDepend)
DotCoverReport (fun p -> { p with
Source = artifactsDir @@ "DotCover.snapshot"
Output = artifactsDir @@ "DotCover.htm"
ReportType = DotCoverReportType.Html })
)
[/code]
All that’s left is to define the dependency hierarchy in F# make:
[code language=”fsharp”]"EnsureDependencies"
==> "TestCoverage"[/code]
And off you go – calling your build script with the “TestCoverage” target should run all your tests and generate the coverage reports.
2 replies on “Code coverage using dotCover and F# make”
[…] James Crowley blogged “Code coverage using dotCover and F# make“. […]
[…] Code coverage using dotCover and F# make (Covering yourself with nothing but a dot – not just for nudists, anymore) […]