You may download the latest release from the following URL. heute.tar.gz.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
(use-package 'heute) ;; symbols from the HEUTE package are in ALL-CAPS ;; define a subclass of HEUTE:TESTCASE (defclass my-top-suite (TESTCASE) ((TEST-NAME ;; human readable name of this test suite ;; all suites should have different names. :initform "Top Suite") (TEST-FUNS ;; list all the test function, each should be a method on this class :initform '(test1 test2)))) (defmethod test1 ((testcase my-top-suite)) ;; make one or more assetions using the ASSERT... or FAIL-IF-.. APIs. (ASSERT-FALSE testcase ;; some form to evaluate in this lexical scope (> 1 2) ;; you may identify a particular assertion with a uniqe tag :tag 100 ;; a form to eval to get a human readable error message ;; in case the assertion fails. :text "1 is not greater than 2") (ASSERT-TRUE testcase (member 3 '( 1 5 3 7)) :tag 101 :text "some interesting failure message")) (defmethod test2 ((testcase my-top-suite)) (ASSERT-EQUAL testcase (- 10 5) (+ 2 3) :tag 200 :text "arithmetic error") (ASSERT-NOT-EQUAL testcase (/ 10 2) (1+ (/ 10 2)) :tag 201 :text "an different arithmetic error")) ;; Setup function. ;; Runs before my-top-suite or any of its subclasses are tested. (defmethod RUN-SUITE :before ((testcase my-top-suite)) (format t "hello this is *before* my-top-suite~%")) ;; Mopup function. ;; Runs after my-top-suite and all its subclasses are tested. (defmethod RUN-SUITE :after ((testcase my-top-suite)) (format t "hello this is *after* my-top-suite~%")) ;; Setup and Mopup together in an around method. ;; But don't forget to call call-next-method and return its value. (defmethod RUN-TEST :around ((testcase my-top-suite) test-fun) (format t "[ hello this is *around* each of the test* functions~%") (prog1 (call-next-method) (format t "done with ~A]~%" test-fun))) ;; Run the test suite, or you can also specify a class name (RUN-ALL-UNIT-TESTS t)
TESTCASE
. You are required to override at least the one
field TEST-NAME
in your subclass to be a textual, human-readable,
description of the tests the suite will cover. Generally you should
create one class per package in your application.
In each sublcass of TESTCASE
you may override the slot
TEST-FUNS
to be a list of (symbols) function names. Each
such function name must name a method callable on the class. Of
course the method might actually only be defined on a super-class.
Each test-function (whose name is in TEST-FUNS
) is
expected to make calls to none, one, or many of the following
functions (actually macros). Each macro evaluates the given
expression expression in the lexical environment of the macro
expansion. In each case a different situation is checked to decide if
it is a PASS or FAIL condition.
ASSERT-FALSE
testcase expression &key tag text
action-on-fail)
FAIL-IF
testcase expression &key tag text action-on-fail)
ASSERT-TRUE
testcase expression &key tag text action-on-fail)
FAIL-IF-NOT
testcase expression &key tag text action-on-fail)
ASSERT-NOT-CONDITION
testcase condition expression &key tag text action-on-fail)
FAIL-IF-CONDITION
testcase condition expression &key tag text action-on-fail)
ASSERT-CONDITION
testcase condition expression &key tag text action-on-fail)
FAIL-IF-NOT-CONDITION
testcase condition expression &key tag text action-on-fail)
ASSERT-NOT-EQUAL
testcase lhs rhs &key tag text action-on-fail test)
FAIL-IF-EQUAL
testcase lhs rhs &key tag text action-on-fail test)
ASSERT-EQUAL
testcase lhs rhs &key tag text action-on-fail test)
FAIL-IF-NOT-EQUAL
testcase lhs rhs &key tag text action-on-fail test)
:abort-test
and if the test FAILS the test-fun
will perform a non-local exit and the next test-fun will
commence. This will have the effect of causing the AFTER
methods of RUN-TEST
to be skipped.
An example some unit tests is provided with HEUTE.
Each stage of the HEUTE engine is actually the envocation of a generic function. You may implement SETUP and MOPUP function on a per-suite or a per-test basis by defining before and after methods on the following generic functions, specializing on your TESTCASE subclass.
RUN-SUITE
testcase)
RUN-TEST
testcase test-fun)
TESTCASE
class. Each class might have sub-suites
defined as identified by the subclasses of the class, and might have
TEST-FUNS
. The algorithm first runs recursively on each
subclass, then on its own TEST-FUNS. A test-suite is considered PASS
if all the sub-suites pass and all the TEST-FUNS pass. A test-suite
is considered FAIL if any of the sub-suites or any of the TEST-FUNS
fail.
DEFCLASS
register it by name with the function
REGISTER-GUI
. E.g.,
(use-package 'heute) (defclass my-gui-class () ()) (register-gui 'my-gui-class)
Doing so desructively modifies the CLOS class hierarchy of the HEUTE framework allowing you to write auxillary methods specializing on your class. There are several generic functions of interest for this purpose.
RUN-ALL-UNIT-TESTS
testcase )
:BEFORE
method on RUN-ALL-UNIT-TESTS
specializing
on your graphic-ui class allows you to initialize the necessary
graphial environment.
RUN-SUITE
testcase )
RUN-SUITE :BEFORE
method allows the
graphical environemnt to draw a graphical item representing the
test suite. Defining a RUN-SUITE :AFTER
method allows the
the graphical environment to paint the graphical item red or
green to indicate PASS or FAIL.
RUN-TEST
testcase test-fun )
PARENT-SUITE
testcase)
SUITE-LEVEL
testcase)
STATUS
testcase)
*test-statuses*
.
While the test is running this return the value
:RUNNING
. After the test completes, either
:PASS
or :FAIL
is returned.
NUMBER-OF-SIBLINGS
testcase)
SIBLING-INDEX
testcase)
NUMBER-OF-SIBLINGS
testcase),
exclusive, corresponding to the index of the given
test.
Two UI front-ends are provided with HEUTE by default:
Here is a picture of what the LTK front end looks like. Red rectangles signify tests that failed. Yellow signifies tests that are running or waiting to run. Green signifies tests that have passed. You can click the mouse on any of the rectangles to re-run that test and all its sub-tests.
Example of LTK Graphical frontend |
---|
After tests are complete red and green indicate pass/fail status. |
![]() |
Example of LTK Graphical frontend |
---|
While the tests are running, yello indicates that a test is waiting to run or running. |
![]() |