Bam - Property-Based Testing Library for OCaml

Overview

Bam is an OCaml library designed for property-based testing (PBT). Property-based testing is a methodology where properties are verified across numerous randomly generated values. When a counterexample is found, a shrinker can be employed to produce smaller, more comprehensible counterexamples, thus facilitating easier debugging.

Key Features

Installation

With opam

opam install bam tezt-bam

Compatibility is ensured for OCaml versions 4.14.2, 5.0.0 and 5.1.0.

Usage

A simple test can be run as follows:

open Tezt_bam


type t = Foo of {a: int; b : string} | Bar of int list[@@deriving gen]
(** The deriver creates a value [val gen : t Bam.Std.t]. *)

let register () =
  let property = function
  | Foo {a; b} ->
      if a > 1_000 && String.contains b 'z' then
        Error (`Fail "A counter-example was found")
      else Ok ()
  | Bar [1; 2; 3; 4] ->
      Error `Bad_value
  | Bar _ ->
      Ok ()
  in  
  Pbt.register ~__FILE__ ~title:"Simple example of bam" ~tags:["bam"; "simple"]
    ~gen ~property ()

let _ = 
    register ();
    Test.run ()
executation of bam example

or without using the PPX deriver, the same example could be written as follows:

open Tezt_bam


type t = Foo of {a: int; b : string} | Bar of int list

let gen =
  let open Bam.Std.Syntax in
  let gen_Foo =
    let* a = Bam.Std.int () in
    let* b = Bam.Std.string ~size:(Bam.Std.int ~max:10 ()) () in
    return (Foo {a; b})
  in
  let gen_Bar =
    let* arg_0 =      
      Bam.Std.list ~size:(Bam.Std.int ~max:10 ()) (Bam.Std.int ())
    in
    return (Bar arg_0)
  in
  Bam.Std.oneof [(1, gen_Foo); (1, gen_Bar)]

let register () =  
  let property = function
  | Foo {a; b} ->
      if a > 1_000 && String.contains b 'z' then
        Error (`Fail "A counter-example was found")
      else Ok ()
  | Bar [1; 2; 3; 4] ->
      Error `Bad_value
  | Bar _ ->
      Ok ()
  in  
  Pbt.register ~__FILE__ ~title:"Simple example of bam" ~tags:["bam"; "simple"]
    ~gen ~property ()

let _ = 
    register ();
    Test.run ()

This example and how it can be run are explained through the various examples. We invite you to read them if you are interested in starting with the library!

PPX

At the moment, the PPX support is partial but should cover a vast majority of use cases. Moreover, the deriver supports many attributes to tune its behavior. In particular, one can specify a generator when it is not supported by the deriver.

There is no proper documentation for the PPX yet. Instead, we invite you to look at the many examples here to see what types are supported and how the deriver can be tuned.

Contributions are welcome!

License

License: MIT