# Idiomatic way to write proper F# (x)unit + fsunit tests?

I am writing some unit tests using XUnit in F# and I am wondering what is the most idiomatic way in the F# sense to write them.

Let's start a simple case:

BicValidationTests.fs:

module Rm.Bai.Domain.BicValidationTests
open Rm.Bai.Domain.BicValidation
open FsUnit
open Xunit

let shortValidBic    = "MYMB gb 2L"
let expectedShortBic = "MYMBGB2L"
let ok               = Result<string, ValidationError>.Ok
let error            = Result<string, ValidationError>.Error

[<Fact>]
let Short Bic should be valid when all rules are respected () =
shortValidBic
|> validateAndFormat
|> should equal (ok expectedShortBic)


One thing I am not too sure is whether it is better to include directly the values knowing that there is nothing shared among different test functions right into the test functions, such as:

[<Fact>]
let Short Bic should be valid when all rules are respected () =
"MYMB gb 2L"
|> validateAndFormat
|> should equal (ok "MYMBGB2L")


This seems to be even more so the case since the answer I got here which seems to indicate that if you have several test files, you need to rely on declaring types / classes to contain let variables for things other than primitive types like number or strings.

For example:

let sepaCompliantBics = [
"GFDIATGN";
"XHOCATENR1X";
"IMITBEW1";
"JYPPBEPW807";
"AHODBGG2";
"LTQJBGMRKKA";
"LAHYHRDK";
...
]

[<Fact>]
let Bics should be valid with SEPA-compliant countries () =
sepaCompliantBics
|> List.map(fun bic -> (validateAndFormat bic, bic))
|> List.iter(fun (validation, bic) -> validation |> should equal (ok bic))


sepaCompliantBics in the example above will be set to null if it happens to not be the first file in the test project.

The solutions are then:

type Tests() =
let ok               = Result<string, ValidationError>.Ok
let error            = Result<string, ValidationError>.Error

let sepaCompliantBics = [
"GFDIATGN";
"XHOCATENR1X";
"IMITBEW1";
"JYPPBEPW807";
"AHODBGG2";
"LTQJBGMRKKA";
"LAHYHRDK";
...
]

[<Fact>]
let Bics should be valid with SEPA-compliant countries () =
sepaCompliantBics
|> List.map(fun bic -> (validateAndFormat bic, bic))
|> List.iter(fun (validation, bic) -> validation |> should equal (ok bic))


or:

let getSepaCompliantBics() = [
"GFDIATGN";
"XHOCATENR1X";
"IMITBEW1";
"JYPPBEPW807";
"AHODBGG2";
"LTQJBGMRKKA";
"LAHYHRDK";
...
]

[<Fact>]
let Bics should be valid with SEPA-compliant countries () =
getSepaCompliantBics()
|> List.map(fun bic -> (validateAndFormat bic, bic))
|> List.iter(fun (validation, bic) -> validation |> should equal (ok bic))


or again:

[<Fact>]
let Bics should be valid with SEPA-compliant countries () =
[
"GFDIATGN";
"XHOCATENR1X";
"IMITBEW1";
"JYPPBEPW807";
"AHODBGG2";
"LTQJBGMRKKA";
"LAHYHRDK";
...
// this can be a pretty long list btw
]
|> List.map(fun bic -> (validateAndFormat bic, bic))
|> List.iter(fun (validation, bic) -> validation |> should equal (ok bic))


So I am wondering if having a long list like the example above is problem if it is defined in the test function itself rather than said outside? Is it still an idiomatic way to write unit tests with F#?

I think that regardless of a language you're using the most idiomatic way would be to take advantage of InlineData attribute

It would look roughly like this

[<Theory>]
let Bics should be valid with SEPA-compliant countries input output =