F#: Bank Account Kata (Property-based Tests)

In previous posts, I have discussed my implementation details for the Bank Account kata.

This post will provide details on how I property-based test one of my functions. Specifically, I show the source code for testing a deposit.

Here are the types:

type Account =        
    | Checking of decimal
    | Savings  of decimal
    | Business of decimal

type Commands =
    | Withdraw of Account * decimal
    | Deposit  of Account * decimal
    | Transfer of Account * Account * decimal

type Response =
    | Withdrawal       of State * State
    | WithdrawalFailed of Account * decimal

    | Deposited        of State * State             
    | DepositFailed    of Account * decimal

    | Transferred      of TransferSummary   * decimal
    | TransferFailed   of Account * Account * decimal

and State =
    | BeforeDeposit of Account * decimal
    | AfterDeposit  of Account

    | BeforeWithdrawal of Account * decimal
    | AfterWithdrawal  of Account

and TransferSummary = { 
    FromBalanceBefore: Account ; ToBalanceBefore: Account
    FromBalanceAfter:  Account ; ToBalanceAfter:  Account }

The function is below:

let handleDeposit = function
    | Deposit (account , amount) when amount > 0m && amount <= 1000000000m ->
           Some (Deposited((BeforeDeposit (account , amount),
                            AfterDeposit  (credit account amount) )))
    | Deposit (account , amount) ->
           Some (DepositFailed (account , amount))
    | _ -> None

The following code is a property-based test for the function above:

(*Tests*)
open FsCheck
open FsCheck.Xunit

type Run100KAttribute() =
    inherit PropertyAttribute(
        MaxTest = 100000,
        QuietOnSuccess = true)

[<Run100K>]
let ``deposits greater than zero AND less than 1 million always succeed`` () =

    // Setup
    let validDeposits = function
        | Deposit (acct , bal) -> bal > 0m && 
                                  bal <= 1000000m
        | _ -> false

    let isDeposited deposit = function
        | Some v -> match v with
                    | Deposited _ -> true
                    | _           -> false
        | _ -> false

    // Test
    Arb.generate<Commands> 
    |> Gen.filter validDeposits
    |> Arb.fromGen
    |> Prop.forAll 
    <| fun deposit -> handleDeposit deposit 
                      |> isDeposited
Advertisements

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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: