Fuchu is a test library for .NET, supporting C# and VB.NET but with a special focus on F#.
It draws heavily from Haskell's test-framework and HUnit.
You can read about the rationale and underlying concepts in this blog post.
Binaries are available on NuGet.
Here's the simplest test possible:
open Fuchu
let simpleTest =
testCase "A simple test" <|
fun _ -> Assert.Equal("2+2", 4, 2+2)
Tests can be grouped (with arbitrary nesting):
let tests =
testList "A test group" [
testCase "one test" <|
fun _ -> Assert.Equal("2+2", 4, 2+2)
testCase "another test" <|
fun _ -> Assert.Equal("3+3", 3, 3+3)
]
In C#:
static Test ATest {
get {
return Test.List("A test group", new[] {
Test.Case("one test", () => Assert.Equal("2+2", 4, 2+2)),
Test.Case("another test", () => Assert.Equal("3+3", 3, 3+3)),
});
}
}
The first parameter in the assertions describes the assertion. This is usually an optional parameter in most test frameworks; in Fuchu it's required to foster descriptive failures, so you'll get a failure like "3+3 Expected value 3, actual 6" instead of just "Expected value 3, actual 6".
For more examples, including a few ways to do common things in other test frameworks like setup/teardown and parameterized tests, see the F# tests and the C# tests
Fuchu is mainly oriented to test organization. Although it does have a few basic assertions, you're encouraged to write your own specialized assertions for each project (they're only a couple of lines in F#), or use some other library for assertions, like Unquote, FsUnit, or even MbUnit or NUnit.
The test runner is the test assembly itself. It's recommended to compile your test assembly as a console application. You can run a test directly like this:
run simpleTest // or runParallel
which returns 1 if any tests failed, otherwise 0. Useful for returning to the operating system as error code. Or you can mark the top-level test in each test file with the [<Tests>]
attribute, then define your main like this:
[<EntryPoint>]
let main args = defaultMainThisAssembly args
This defaultMainThisAssembly
function admits a "/m" parameter passed through the command-line to run tests in parallel.
You can single out tests by filtering them by name. For example:
tests
|> Test.filter (fun s -> s.EndsWith "another test")
|> run
You can use the F# REPL to run tests this way.
In C#:
static int Main(string[] args) {
return ATest.Run(); // or RunParallel()
}
Or scanning for tests marked with the [Tests] attribute:
static int Main(string[] args) {
return Tests.DefaultMainThisAssembly(args);
}
Reference FsCheck and Fuchu.FsCheck to test properties:
let config = { FsCheck.Config.Default with MaxTest = 10000 }
let properties =
testList "FsCheck" [
testProperty "Addition is commutative" <|
fun a b ->
a + b = b + a
// you can also override the FsCheck config
testPropertyWithConfig config "Product is distributive over addition" <|
fun a b c ->
a * (b + c) = a * b + a * c
]
run properties
In C# (can't override FsCheck config at the moment):
static Test Properties =
Test.List("FsCheck", new[] {
FsCheck.Property("Addition is commutative",
(int a, int b) => a + b == b + a),
FsCheck.Property("Product is distributive over addition",
(int a, int b, int c) => a * (b + c) == a * b + a * c),
});
You can freely mix FsCheck properties with regular test cases and test lists.
Some projects using Fuchu:
- FsSql
- FsFormlets
- UrchiNet (C# and F#)
- Figment
- NHWebConsole
- Fleece
- EdmundsNet
- Suave