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-NAMEin 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
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-FALSEtestcase expression &key tag text action-on-fail)
FAIL-IFtestcase expression &key tag text action-on-fail)
ASSERT-TRUEtestcase expression &key tag text action-on-fail)
FAIL-IF-NOTtestcase expression &key tag text action-on-fail)
ASSERT-NOT-CONDITIONtestcase condition expression &key tag text action-on-fail)
FAIL-IF-CONDITIONtestcase condition expression &key tag text action-on-fail)
ASSERT-CONDITIONtestcase condition expression &key tag text action-on-fail)
FAIL-IF-NOT-CONDITIONtestcase condition expression &key tag text action-on-fail)
ASSERT-NOT-EQUALtestcase lhs rhs &key tag text action-on-fail test)
FAIL-IF-EQUALtestcase lhs rhs &key tag text action-on-fail test)
ASSERT-EQUALtestcase lhs rhs &key tag text action-on-fail test)
FAIL-IF-NOT-EQUALtestcase lhs rhs &key tag text action-on-fail test)
:abort-testand 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
RUN-TESTto 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.
TESTCASEclass. 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.
DEFCLASSregister it by name with the function
(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-TESTSspecializing on your graphic-ui class allows you to initialize the necessary graphial environment.
RUN-SUITE :BEFOREmethod allows the graphical environemnt to draw a graphical item representing the test suite. Defining a
RUN-SUITE :AFTERmethod allows the the graphical environment to paint the graphical item red or green to indicate PASS or FAIL.
RUN-TESTtestcase test-fun )
*test-statuses*. While the test is running this return the value
:RUNNING. After the test completes, either
NUMBER-OF-SIBLINGStestcase), 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.|