Header menu logo testify

Assertions

This page covers the example-based half of Testify:

Use this layer when you already know the concrete expression you want to show in the test.

Why Not Just Use Plain Asserts?

Plain asserts are fine when:

Testify becomes more interesting when you want:

Assert.result

Assert.result evaluates the quoted expression and gives you an AssertResult.

let result =
    Assert.result
        (AssertExpectation.equalTo "MiniLib")
        <@ "Mini" + "Lib" @>

Use it when you want to:

Example failure-inspection flow:

let result =
    Assert.result
        (AssertExpectation.equalTo 3)
        <@ 1 + 1 @>

let rendered = Assert.toDisplayString result
let report = Assert.toFailureReport result

Assert.should

Assert.should uses the same assertion pipeline, but raises immediately when the assertion fails.

Assert.should
    (AssertExpectation.equalTo "MiniLib")
    <@ "Mini" + "Lib" @>

Use should when:

Operators

For direct tests, the operator layer is usually the most pleasant path:

open Testify.AssertOperators

<@ 1 + 2 @> |>? AssertExpectation.equalTo 3
<@ 1 + 2 @> =? 3
<@ 5 @> <? 10
<@ 5 @> >=? 5
<@ 1 + 2 = 3 @> ?
<@ 1 / 0 @> ^?

Useful reading rule:

If a symbolic form stops being readable, switch back to the named API. Testify does not require you to stay in operators once the test needs more explanation.

What A Better Failure Looks Like

The real value of quotations shows up on failure:

That is why Assert.result is worth having even when Assert.should is the more common path.

Collecting Several Assertion Results

If you want to run several independent checks and fail once at the end:

let collector = Assert.Collect.create ()

Assert.result (AssertExpectation.equalTo 3) <@ 1 + 2 @>
|> Assert.Collect.add collector
|> ignore

Assert.result (AssertExpectation.startsWith "Mini") <@ "MiniLib" @>
|> Assert.Collect.add collector
|> ignore

Assert.Collect.assertAll collector

Good First Expectation Builders

Start with:

Then move on to:

Build A Vocabulary, Not Just Tests

A good Testify codebase usually stops repeating raw comparison logic and starts naming expectations:

let sameAge =
    AssertExpectation.equalBy (fun person -> person.Age)

let visibleUser =
    AssertExpectation.isSome
    <&> AssertExpectation.satisfy "active user" (Option.exists (fun user -> user.IsActive))

That is usually where Assert becomes more valuable than “just another assert helper.”

For the exact signatures and full method-by-method reference, jump to the API Reference.

val result: obj
val rendered: obj
val report: obj
val ignore: value: 'T -> unit
module Option from Microsoft.FSharp.Core
val exists: predicate: ('T -> bool) -> option: 'T option -> bool

Type something to start searching.