Skip to content

Commit

Permalink
Merge pull request #575 from mantzas/xunit2_support
Browse files Browse the repository at this point in the history
Xunit2 support WIP
  • Loading branch information
forki committed Oct 30, 2014
2 parents 3dd64a6 + 078a7ea commit 7f4c281
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/app/FakeLib/FakeLib.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
<Compile Include="UnitTest\NUnit\Sequential.fs" />
<Compile Include="UnitTest\NUnit\Parallel.fs" />
<Compile Include="UnitTest\XUnitHelper.fs" />
<Compile Include="UnitTest\XUnit2Helper.fs" />
<Compile Include="UnitTest\MSpecHelper.fs" />
<Compile Include="UnitTest\MSTest.fs" />
<Compile Include="UnitTest\ProcessTestRunner.fs" />
Expand Down
191 changes: 191 additions & 0 deletions src/app/FakeLib/UnitTest/XUnit2Helper.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/// Contains tasks to run [xUnit](http://xunit.codeplex.com/) unit tests.
module Fake.XUnit2Helper

open System
open System.IO
open System.Text

(*
xUnit.net console test runner (64-bit .NET 4.0.30319.34209)
Copyright (C) 2014 Outercurve Foundation.
usage: xunit.console <assemblyFile> [configFile] [options]
Valid options:
-parallel option : set parallelization based on option
: none - turn off all parallelization
: collections - only parallelize collections
: assemblies - only parallelize assemblies
: all - parallelize assemblies & collections
-maxthreads count : maximum thread count for collection parallelization
: 0 - run with unbounded thread count
: >0 - limit task thread pool size to 'count'
-silent : do not output running test count
-noshadow : do not shadow copy assemblies
-teamcity : forces TeamCity mode (normally auto-detected)
-appveyor : forces AppVeyor CI mode (normally auto-detected)
-wait : wait for input after completion
-trait "name=value" : only run tests with matching name/value traits
: if specified more than once, acts as an OR operation
-notrait "name=value" : do not run tests with matching name/value traits
: if specified more than once, acts as an AND operation
-xml <filename> : output results to xUnit.net v2 style XML file
-xmlv1 <filename> : output results to xUnit.net v1 style XML file
-html <filename> : output results to HTML file
*)

type ParallelOption =
| None = 0
| Collections = 1
| Assemblies = 2
| All = 3

/// Option which allows to specify if an xUnit error should break the build.
type XUnit2ErrorLevel = TestRunnerErrorLevel // a type alias to keep backwards compatibility

/// The xUnit parameter type
type XUnit2Params =
{ /// The path to the xunit.console.exe - FAKE will scan all subfolders to find it automatically.
ToolPath : string
/// The file name of the config file (optional).
ConfigFile : string
/// set parallelization based on option
/// none - turn off all parallelization
/// collections - only parallelize collections
/// assemblies - only parallelize assemblies
/// all - parallelize assemblies & collections
Parallel : ParallelOption
/// maximum thread count for collection parallelization
/// 0 - run with unbounded thread count
/// >0 - limit task thread pool size to 'count'
MaxThreads : int
/// Output running test count
Silent : bool
/// Shadow copy
ShadowCopy : bool
/// forces TeamCity mode (normally auto-detected)
Teamcity : bool
/// forces AppVeyor CI mode (normally auto-detected)
Appveyor : bool
// wait for input after completion
Wait : bool
/// The working directory (optional).
WorkingDir : string
/// If the timeout is reached the xUnit task will be killed. Default is 5 minutes.
TimeOut : TimeSpan
/// Test runner error level. Option which allows to specify if an xUnit error should break the build.
ErrorLevel : XUnit2ErrorLevel
/// Include named traits with comma separated values
IncludeTraits : (string * string) option
/// Exclude named traits with comma separated values
ExcludeTraits : (string * string) option
/// output results to xUnit.net v2 style XML file
XmlOutput : bool
/// output results to xUnit.net v1 style XML file
XmlOutputV1 : bool
/// output results to HTML file
HtmlOutput : bool
/// output directory
OutputDir : string }

/// The xUnit default parameters
let empty2Trait : (string * string) option = None

let XUnit2Defaults =
{ ToolPath = findToolInSubPath "xunit.console.exe" (currentDirectory @@ "tools" @@ "xUnit")
ConfigFile = null
Parallel = ParallelOption.None
MaxThreads = 0
Silent = false
ShadowCopy = true
Teamcity = false
Appveyor = false
Wait = false
WorkingDir = null
TimeOut = TimeSpan.FromMinutes 5.
ErrorLevel = Error
IncludeTraits = empty2Trait
ExcludeTraits = empty2Trait
XmlOutput = false
XmlOutputV1 = false
HtmlOutput = false
OutputDir = null }

/// Builds the command line arguments from the given parameter record and the given assemblies.
/// [omit]
let buildXUnit2Args parameters assembly =
let fi = fileInfo assembly
let name = fi.Name

let dir =
if isNullOrEmpty parameters.OutputDir then String.Empty
else Path.GetFullPath parameters.OutputDir

let traits includeExclude (name, values : string) =
values.Split([| ',' |], System.StringSplitOptions.RemoveEmptyEntries)
|> Seq.collect (fun value ->
[| includeExclude
sprintf "\"%s=%s\"" name value |])
|> String.concat " "

let parallelOptionsText =
parameters.Parallel.ToString().ToLower()

new StringBuilder()
|> appendFileNamesIfNotNull [ assembly ]
|> append "-parallel"
|> append (sprintf "%s" parallelOptionsText)
|> append "-maxthreads"
|> append (sprintf "%i" parameters.MaxThreads)
|> appendIfFalse parameters.ShadowCopy "-noshadow"
|> appendIfTrue (buildServer = TeamCity) "-teamcity"
|> appendIfTrue (buildServer = AppVeyor) "-appveyor"
|> appendIfTrue parameters.Wait "-wait"
|> appendIfTrue parameters.Silent "-silent"
|> appendIfTrue parameters.XmlOutput (sprintf "-xml\" \"%s" (dir @@ (name + ".xml")))
|> appendIfTrue parameters.XmlOutputV1 (sprintf "-xmlv1\" \"%s" (dir @@ (name + ".xml")))
|> appendIfTrue parameters.HtmlOutput (sprintf "-html\" \"%s" (dir @@ (name + ".html")))
|> appendIfSome parameters.IncludeTraits (traits "-trait")
|> appendIfSome parameters.ExcludeTraits (traits "-notrait")
|> toText


/// Runs xUnit unit tests in the given assemblies via the given xUnit runner.
/// Will fail if the runner terminates with non-zero exit code for any of the assemblies.
/// Offending assemblies will be listed in the error message.
///
/// The xUnit runner terminates with a non-zero exit code if any of the tests
/// in the given assembly fail.
/// ## Parameters
///
/// - `setParams` - Function used to manipulate the default XUnitParams value.
/// - `assemblies` - Sequence of one or more assemblies containing xUnit unit tests.
///
/// ## Sample usage
///
/// Target "Test" (fun _ ->
/// !! (testDir + @"\xUnit.Test.*.dll")
/// |> xUnit (fun p -> {p with OutputDir = testDir })
/// )
let xUnit2 setParams assemblies =
let details = separated ", " assemblies
traceStartTask "xUnit2" details
let parameters = setParams XUnit2Defaults

let runTests assembly =
let args = buildXUnit2Args parameters assembly
0 = ExecProcess (fun info ->
info.FileName <- parameters.ToolPath
info.WorkingDirectory <- parameters.WorkingDir
info.Arguments <- args) parameters.TimeOut

let failedTests =
[ for asm in List.ofSeq assemblies do
if runTests asm |> not then yield asm ]

if not (List.isEmpty failedTests) then
sprintf "xUnit2 failed for the following assemblies: %s" (separated ", " failedTests)
|> match parameters.ErrorLevel with
| Error | FailOnFirstError -> failwith
| DontFailBuild -> traceImportant
traceEndTask "xUnit2" details
1 change: 1 addition & 0 deletions src/test/Test.FAKECore/Test.FAKECore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
<Compile Include="FileHandling\CleanDirectorySpecs.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="FileHandling\GlobbingSpecs.cs" />
<Compile Include="XUnit2HelperSpecs.cs" />
<Compile Include="XUnitHelperSpecs.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
29 changes: 29 additions & 0 deletions src/test/Test.FAKECore/XUnit2HelperSpecs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using Fake;
using Machine.Specifications;
using Microsoft.FSharp.Core;

namespace Test.FAKECore
{
public class XUnit2HelperSpecs
{
It args_should_not_include_traits = () => BuildXUnit2Args(XUnit2Helper.empty2Trait, XUnit2Helper.empty2Trait).ShouldNotContain("trait");
It args_should_include_one_trait = () => BuildXUnit2Args(Trait("name", "value"), XUnit2Helper.empty2Trait).ShouldContain(@" -trait ""name=value""");
It args_should_include_two_traits = () => BuildXUnit2Args(Trait("name", "value1,value2"), XUnit2Helper.empty2Trait).ShouldContain(@" -trait ""name=value1"" -trait ""name=value2""");
It args_should_exclude_one_trait = () => BuildXUnit2Args(XUnit2Helper.empty2Trait, Trait("name", "value")).ShouldContain(@"-notrait ""name=value""");
It args_should_exclude_two_traits = () => BuildXUnit2Args(XUnit2Helper.empty2Trait, Trait("name", "value1,value2")).ShouldContain(@" -notrait ""name=value1"" -notrait ""name=value2""");
It args_should_contain_paraller = () => BuildXUnit2Args(XUnit2Helper.empty2Trait, XUnit2Helper.empty2Trait).ShouldContain(@"-parallel");

private static FSharpOption<Tuple<string, string>> Trait(string name, string values)
{
return new FSharpOption<Tuple<string, string>>(new Tuple<string, string>(name,values));
}

private static string BuildXUnit2Args(FSharpOption<Tuple<string, string>> includeTrait, FSharpOption<Tuple<string, string>> excludeTrait)
{
var parameters = new XUnit2Helper.XUnit2Params("", "", XUnit2Helper.ParallelOption.None, 0, false, false,
true, false, false,null, TimeSpan.FromMinutes(5), UnitTestCommon.TestRunnerErrorLevel.Error, includeTrait, excludeTrait, false, false, true, "");
return XUnit2Helper.buildXUnit2Args(parameters, "test.dll");
}
}
}

0 comments on commit 7f4c281

Please sign in to comment.