06 Black Box Testing

Tests are based on the specification of the function.

There are a bunch of advantages to that!

Main kinds of black box tests:

Typical inputs

Common, simple values of a type. If you're writing a function that tests:

Boundry cases

Boundry testing involves testing boundary cases, also known as corner cases or edge cases. They are atypical or extremal values of a type and values.

Paths through spec

Representitive inputs for all classes of outputs. For example, let's specify a function:

(** [is_prime n] is true iff [n] is prime *)
val is_prime: int -> bool

This function has two classes of output:

Other examples:

Representitive inputs for each way of satisfying the precondition.

(** [sqrt x n] is the square root of [x] computed to an
    accuracy of [n] significant figures.

    requires: x >= 0 and n >= 1 *)
val sqrt : float -> int -> float

There are four ways of satisfying the precondition (with respect to the >=)

Representitive inputs for each way of raising and not raising an exception

(** [pos x lst] is the 0-based position of the first element
    of [lst] that equals [x].

    raises: Not_found if [x] is not in [lst] *)
val pos : 'a -> 'a list -> int

Data abstractions

When testing data abstractions, test the interaction of producers and consumers