Header menu logo testify

Cookbook Examples

This page is a concentrated set of “show me the shape” examples.

If you want the most persuasive examples first, jump to Power Showcase.

Basics

Direct Equality Assertion

<@ List.length [1; 2; 3] @> =? 3

Assertion With A Reusable Expectation

let positiveSmall =
    AssertExpectation.greaterThan 0
    <&> AssertExpectation.lessThan 10

<@ 5 @> |>? positiveSmall

Domain Modeling

type Person = { Name: string; Age: int }

## Compare Domain Objects By One Field

<@ { Name = "Tony"; Age = 48 } @>
|>? AssertExpectation.equalBy (fun person -> person.Age) { Name = "Anthony"; Age = 48 }

Compare To One Projected Key

<@ "Testify" @>
|>? AssertExpectation.equalByKey String.length 7

Compare With A Custom Relation

<@ { Name = "Tony"; Age = 48 } @>
|>? AssertExpectation.equalWith (fun a b -> a.Age = b.Age) { Name = "Anthony"; Age = 48 }

Property Power

Simple Property Check Against A Reference

<@ List.rev >> List.rev @> |=> id

Property Check With A Custom Arbitrary

let pairArb =
    Arbitraries.tuple2
        (Arbitraries.from<int>)
        (Arbitraries.from<int>)

Check.should(
    CheckExpectation.equalToReference,
    (fun (a, b) -> a + b),
    <@ fun (a, b) -> a + b @>,
    arbitrary = pairArb)

Custom Generator Then Arbitrary

let fixedLengthLists =
    Generators.listOfLength 5 (Generators.from<int>)
    |> Arbitraries.fromGen

Check.should(
    CheckExpectation.equalToReference,
    List.length,
    <@ List.length @>,
    arbitrary = fixedLengthLists)

Advanced Dependent Property

Check.shouldBy(
    (fun verify ->
        FsCheck.Prop.forAll Arbitraries.from<int> (fun n ->
            let length = abs n
            let arb = Arbitraries.fromGen (FsCheck.Gen.listOfLength length FsCheck.Arb.generate<int>)
            FsCheck.Prop.forAll arb (fun xs ->
                verify (length, xs)))),
    CheckExpectation.isTrue,
    (fun _ -> true),
    <@ fun (expectedLength, xs) -> List.length xs = expectedLength @>)

Inspect A Property Failure Without Throwing

let result =
    Check.result(
        CheckExpectation.equalToReference,
        (fun x -> x + 1),
        <@ fun x -> x + 2 @>)

match result with
| Passed -> printfn "ok"
| _ -> printfn "%s" (Check.toDisplayString result)

Replay A Failing Property Run

match result with
| Failed failure ->
    match failure.TryGetReplayConfig() with
    | Some replayConfig ->
        let replayed =
            Check.result(
                CheckExpectation.equalToReference,
                (fun x -> x + 1),
                <@ fun x -> x + 2 @>,
                config = replayConfig)

        printfn "%s" (Check.toDisplayString replayed)
    | None ->
        ()
| _ ->
    ()

Hints And Global Configuration

Turn On Built-In Hint Packs

Testify.configure (
    TestifyConfig.defaults
    |> TestifyConfig.withHintPacks BuiltInHintPacks.beginner
)

Add A Custom Hint Rule

let trailingSpaceHint =
    TestifyHintRule.onFieldRegexPattern
        "Course.TrailingSpace"
        HintTextField.ActualValue
        @"\s+$"
        (fun _ -> "The actual value appears to end with trailing whitespace.")

let customHints =
    TestifyHintPack.create "course" [ trailingSpaceHint ]

Testify.configure (
    TestifyConfig.defaults
    |> TestifyConfig.withHintPacks (BuiltInHintPacks.beginner @ [ customHints ])
)

Integrations

Expecto

open Expecto
open Testify.Expecto

[<Tests>]
let tests =
    TestifyExpecto.testList "demo" [
        TestifyExpecto.testCase "projection equality" (fun () ->
            <@ { Name = "Tony"; Age = 48 } @>
            |>? AssertExpectation.equalBy (fun person -> person.Age) { Name = "Anthony"; Age = 48 })
    ]
Multiple items
module List from Microsoft.FSharp.Collections

--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T with get member IsEmpty: bool with get member Item: index: int -> 'T with get ...
val length: list: 'T list -> int
val positiveSmall: obj
type Person = { Name: string Age: int }
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
module String from Microsoft.FSharp.Core
val length: str: string -> int
val rev: list: 'T list -> 'T list
val id: x: 'T -> 'T
val pairArb: 'a
val fixedLengthLists: 'a
val abs: value: 'T -> 'T (requires member Abs)
val result: 'a
val Passed: 'a
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
val failure: 'a
union case Option.Some: Value: 'T -> Option<'T>
val replayConfig: 'a
val replayed: 'a
union case Option.None: Option<'T>
val trailingSpaceHint: 'a
val customHints: 'a
val tests: 'a

Type something to start searching.