racket/collects/schemeunit/scribblings/compound-testing.scrbl
2009-03-25 12:34:52 +00:00

169 lines
5.0 KiB
Racket

#lang scribble/doc
@(require "base.ss")
@title{Compound Testing Forms}
@section{Test Cases}
As programs increase in complexity the unit of testing
grows beyond a single check. For example, it may be the case
that if one check fails it doesn't make sense to run
another. To solve this problem compound testing forms can
be used to group expressions. If any expression in a group
fails (by raising an exception) the remaining expressions
will not be evaluated.
@defform[(test-begin expr ...)]{
A @scheme[test-begin] form groups the @scheme[expr]s into a
single unit. If any @scheme[expr] fails the following ones
are not evaluated. }
For example, in the following code the world is not
destroyed as the preceding check fails:
@schemeblock[
(test-begin
(check-eq? 'a 'b)
(code:comment "This line won't be run")
(destroy-the-world))
]
@defform[(test-case name expr ...)]{
Like a @scheme[test-begin] except a name is associated with
the group of @scheme[expr]s. The name will be reported if
the test fails. }
Here's the above example rewritten to use @scheme[test-case]
so the test can be named.
@schemeblock[
(test-case
"Example test"
(check-eq? 'a 'b)
(code:comment "This line won't be run")
(destroy-the-world))
]
@defproc[(test-case? (obj any)) boolean?]{
True if @scheme[obj] is a test case, and false otherwise
}
@section{Test Suites}
Test cases can themselves be grouped into test suites. A
test suite can contain both test cases and test suites.
Unlike a check or test case, a test suite is not immediately
run. Instead use one of the functions described in
@secref["ui"] or @secref["running"].
@defform[(test-suite name [#:before before-thunk] [#:after after-thunk] test ...)]{
Constructs a test suite with the given name and tests. The
tests may be test cases, constructed using
@scheme[test-begin] or @scheme[test-case], or other test
suites.
The @scheme[before-thunk] and @scheme[after-thunk] are
optional thunks (functions are no argument). They are run
before and after the tests are run, respectively.
Unlike a check or test case, a test suite is not immediately
run. Instead use one of the functions described in
@secref["ui"] or @secref["running"].}
For example, here is a test suite that displays @tt{Before}
before any tests are run, and @tt{After} when the tests have
finished.
@schemeblock[
(test-suite
"An example suite"
#:before (lambda () (display "Before"))
#:after (lambda () (display "After"))
(test-case
"An example test"
(check-eq? 1 1)))
]
@defproc[(test-suite? (obj any)) boolean?]{ True if
@scheme[obj] is a test suite, and false otherwise}
@subsection{Utilities for Defining Test Suites}
There are some macros that simplify the common cases of
defining test suites:
@defform[(define-test-suite name test ...)]{ The
@scheme[define-test-suite] form creates a test suite with
the given name (converted to a string) and tests, and binds
it to the same name.}
For example, this code creates a binding for the name
@scheme[example-suite] as well as creating a test suite with
the name @scheme["example-suite"]:
@schemeblock[
(define-test-suite example-suite
(check = 1 1))
]
@defform[(define/provide-test-suite name test ...)]{ This
for is just like @scheme[define-test-suite], and in addition
it @scheme[provide]s the test suite.}
Finally, there is the @scheme[test-suite*] macro, which
defines a test suite and test cases using a shorthand
syntax:
@defform[(test-suite* name (test-case-name test-case-body
...) ...)]{ Defines a test suite with the given name, and
creates test cases within the suite, with the given names and
body expressions.
As far I know no-one uses this macro, so it might disappear
in future versions of SchemeUnit.}
@section{Compound Testing Evaluation Context}
Just like with checks, there are several parameters that
control the semantics of compound testing forms.
@defparam[current-test-name name (or/c string? false/c)]{
This parameter stores the name of the current test case. A
value of @scheme[#f] indicates a test case with no name,
such as one constructed by @scheme[test-begin]. }
@defparam[current-test-case-around handler (-> (-> any/c) any/c)]{
This parameter handles evaluation of test cases. The value
of the parameter is a function that is passed a thunk (a
function of no arguments). The function, when applied,
evaluates the expressions within a test case. The default
value of the @scheme[current-test-case-around] parameters
evaluates the thunk in a context that catches exceptions and
prints an appropriate message indicating test case failure.}
@defproc[(test-suite-test-case-around [thunk (-> any/c)]) any/c]{
The @scheme[current-test-case-around] parameter is
parameterized to this value within the scope of a
@scheme[test-suite]. This function creates a test case
structure instead of immediately evaluating the thunk.}
@defproc[(test-suite-check-around [thunk (-> any/c)]) any/c]{
The @scheme[current-check-around] parameter is parameterized
to this value within the scope of a @scheme[test-suite].
This function creates a test case structure instead of
immediately evaluating a check.}