Learning F#: The Game of Life (Vol. 11)


In the last article, I discussed property-based testing. What I did not discuss was setting up the preconditions necessary for a function to be tested.

Test Conditions

Consider the following function:

let createGrid rowCount = 

    [for x in 0..rowCount-1 do
        for y in 0..rowCount-1 do
            yield { X=x; Y=y; State=Dead }
    ]|> List.map (fun c -> (c.X, c.Y), { X=c.X; Y=c.Y; State=Dead })
     |> Map.ofList

The above function generates a grid from the rowCount argument provided by a client. If we wanted to provide a property-based test for this function, we could write it such that the number of cells generated from the function equals the rowCount that we passed in as input, squared.

The following code is a property-based test:

let ``number of cells in grid equals rowcount squared`` () =
    Check.QuickThrowOnFailure <| fun rowCount -> rowCount |> createGrid
                                                          |> Map.toList
                                                          |> List.length = rowCount * rowCount

If we run the above test, we will observe the following failure.

System.Exception : Falsifiable, after 3 tests (1 shrink) (StdGen (199136793,296133941)):

Setting Preconditions

For the above test to pass, we need to setup some conditions for the range of inputs. For example, this function probably shouldn’t accept negative values for the number of rows. Therefore, to specify the conditions for the valid range of inputs to our function under test, we can rewrite the test and specify the conditions for a valid range of inputs.

The following test includes conditions for valid inputs:

let ``number of cells in grid equals rowcount squared`` () =
    Check.QuickThrowOnFailure <| fun rowCount -> rowCount >= 0 ==> (rowCount |> createGrid
                                                                             |> Map.toList
                                                                             |> List.length = rowCount * rowCount)

Observe the precondition that we provided:

rowCount >= 0

We then feed that precondition into our test with the following operator:


If we run the test now, the test will pass.


In conclusion, I discussed setting up conditions for valid inputs in regards to property-based testing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: