elm-community/elm-test/2.0.1

NOTE: this package is not compatible with Elm 0.19.1

Fuzz

This is a library of fuzzers you can use to supply values to your fuzz tests. You can typically pick out which ones you need according to their types.

A Fuzzer a knows how to create values of type a in two different ways. It can create them randomly, so that your test's expectations are run against many values. Fuzzers will often generate edge cases likely to find bugs. If the fuzzer can make your test fail, it also knows how to "shrink" that failing input into more minimal examples, some of which might also cause the tests to fail. In this way, fuzzers can usually find the smallest or simplest input that reproduces a bug.

Common Fuzzers

bool : Fuzzer Bool

A fuzzer for bool values.

int : Fuzzer Int

A fuzzer for int values.

intRange : Int -> Int -> Fuzzer Int

A fuzzer for int values within between a given minimum and maximum value, inclusive. Shrunken values will also be within the range.

float : Fuzzer Float

A fuzzer for float values. It will never produce NaN, Infinity, or -Infinity.

floatRange : Float -> Float -> Fuzzer Float

A fuzzer for float values within between a given minimum and maximum value, inclusive. Shrunken values will also be within the range.

percentage : Fuzzer Float

A fuzzer for percentage values. Generates random floats between 0.0 and 1.0. It will test zero and one about 10% of the time each.

string : Fuzzer String

A fuzzer for string values. Generates random printable ascii strings whose length is between 0 and 10.

maybe : Fuzzer a -> Fuzzer (Maybe a)

Given a fuzzer of a type, create a fuzzer of a maybe for that type.

result : Fuzzer error -> Fuzzer value -> Fuzzer (Result error value)

Given fuzzers for an error type and a success type, create a fuzzer for a result.

list : Fuzzer a -> Fuzzer (List a)

Given a fuzzer of a type, create a fuzzer of a list of that type. Generates random lists of varying length, favoring shorter lists.

array : Fuzzer a -> Fuzzer (Array a)

Given a fuzzer of a type, create a fuzzer of an array of that type. Generates random arrays of varying length, favoring shorter arrays.

Working with Fuzzers

type alias Fuzzer a =
Fuzzer a

The representation of fuzzers is opaque. Conceptually, a Fuzzer a consists of a way to randomly generate values of type a, and a way to shrink those values.

map : (a -> b) -> Fuzzer a -> Fuzzer b

Map a function over a fuzzer. Due to technical limitations, the resulting fuzzer performs no shrinking.

frequency : List ( Float, Fuzzer a ) -> Result String (Fuzzer a)

Create a new fuzzer by providing a list of fuzzers to pick from. Each fuzzer is associated with a Float weight; larger numbers mean the fuzzer in more likely to get picked from.

For example, to create a Fuzzer that has a 1/4 chance of generating an int between -1 and -100, and a 3/4 chance of generating one between 1 and 100, you could do this:

Fuzz.frequency
    [ ( 1, Fuzz.intRange -100 -1 )
    , ( 3, Fuzz.intRange 1 100 )
    ]

This function returns a Result because it can fail in a few ways:

  • If you provide an empy list of frequencies
  • If any of the weights are less than 0
  • If the weights sum to 0

Any of these will lead to an Err, with a String explaining what went wrong.

frequencyOrCrash : List ( Float, Fuzzer a ) -> Fuzzer a

Calls frequency and handles Err results by crashing with the given error message.

This is useful in tests, where a crash will simply cause the test run to fail. There is no danger to a production system there.

Tuple Fuzzers

Instead of using a tuple, consider using fuzzN.

tuple : ( Fuzzer a, Fuzzer b ) -> Fuzzer ( a, b )

Turn a tuple of fuzzers into a fuzzer of tuples.

tuple3 : ( Fuzzer a, Fuzzer b, Fuzzer c ) -> Fuzzer ( a, b, c )

Turn a 3-tuple of fuzzers into a fuzzer of 3-tuples.

( Fuzzer a, Fuzzer b, Fuzzer c, Fuzzer d )
-> Fuzzer ( a, b, c, d )

Turn a 4-tuple of fuzzers into a fuzzer of 4-tuples.

( Fuzzer a, Fuzzer b, Fuzzer c, Fuzzer d, Fuzzer e )
-> Fuzzer ( a, b, c, d, e )

Turn a 5-tuple of fuzzers into a fuzzer of 5-tuples.

Uncommon Fuzzers

custom : Generator a -> Shrinker a -> Fuzzer a

Build a custom Fuzzer a by providing a Generator a and a Shrinker a. Generators are defined by mgold/elm-random-pcg, which is not core's Random module but has a compatible interface. Shrinkers are defined in elm-community/shrink.

Here is an example for a record:

import Random.Pcg as Random
import Shrink


type alias Position =
    { x : Int, y : Int }




position : Fuzzer Position
position =
    Fuzz.custom
        (Random.map2 Position (Random.int -100 100) (Random.int -100 100))
        (\{ x, y } -> Shrink.map Position (Shrink.int x) `Shrink.andMap` (Shrink.int y))

Here is an example for a custom union type:

type Question
    = Name String
    | Age Int




question =
    let
        generator =
            Random.bool `Random.andThen` (\b ->
                if b then
                    Random.map Name string.generator
                else
                    Random.map Age (Random.int 0 120)
             )


        shrinker question =
            case question of
                Name n ->
                    Shrink.string n |> Shrink.map Name


                Age i ->
                    Shrink.int i |> Shrink.map Age
    in
        Fuzz.custom generator shrinker
char : Fuzzer Char

A fuzzer for char values. Generates random ascii chars disregarding the control characters.

unit : Fuzzer ()

A fuzzer for the unit value. Unit is a type with only one value, commonly used as a placeholder.

order : Fuzzer Order

A fuzzer for order values.