Go to the first, previous, next, last section, table of contents.


Writing tests

Before starting on writing test cases you need some familiarity with the GNUstep base library, Guile, Gstep-Guile and Greg. I recommend that you get the documentation for all these packages together on your machine and set bookmarks in your favorite web browser to point to it (and to this documentation of course).

The test suite for the gstep-base library consists of the basic framework plus directories containing tests for individual classes.

Mostly you should be able to pick up how to use this stuff simply by looking at the existing tests - pay special attention to what the initialisation file (`begin.grg') is doing.

One thing to note, if you are not familiar with Guile, is the scope of variables - if you want to pass information from one testcase to another you need to declare the variables outside the testcases (using the `define' primitive) -


(define arith-ok #f)	; For passing info between testcases

;
; A testcase to check an instance of numeric addition
;
(greg-testcase "One plus One is two" #t
(lambda ()
  (if (eq? (+ 1 1 ) 2)
    (begin (set! arith-ok #t) #t)
    #f)
))

;
; A testcase to check arithmetic - only supported if we have addition.
;
(greg-testcase "X multiplied by 2 is X plus X" #t
(lambda ()
  (if arith-ok
    (eq? (+ 1 1) (* 1 2))
    (throw 'unsupported))
))

Similarly, if you wish to restrict the scope of a variable to a group of testcases, wrap the whole lot in a `begin' -


(begin
  (define arith-ok #f)	; For passing info between testcases

;
; A testcase to check an instance of numeric addition
;
  (greg-testcase "One plus One is two" #t
  (lambda ()
    (if (eq? (+ 1 1 ) 2)
      (begin (set! arith-ok #t) #t)
      #f)
  ))

;
; A testcase to check arithmetic - only supported if we have addition.
;
  (greg-testcase "X multiplied by 2 is X plus X" #t
  (lambda ()
    (if arith-ok
      (eq? (+ 1 1) (* 1 2))
      (throw 'unsupported))
  ))
)

; The 'arith-ok' variable is no longer in scope.

initialisation

The initialisation file `begin.grg' is run before any of the tests are started. This file performs basic startup tasks including -

Tests for an individual class are placed in a directory whose name is the name of the class. Since the test scripts within a directory are normally executed in alphabetical order, you may want to add a `begin.grg' to override that default sequence of execution of scripts. If this has been done, you must modify the `begin.grg' file whenever you add a new script to the dictionary, so you may prefer to select your script names so that the default alphabetical ordering causes them to run in the correct sequence.
By convention we use - `basic.scm' for a script calling helper procedures to test that the class exists and conforms to the protocols it should.
`testXX.scm' where `XX' is a number from `00' to `99' for the other test scripts - so that they will be run in the order indicated by the numeric parts of their names.

A script file will contain one or more testcases - each of which constitutes a test of a single well defined feature of the `tool' that the script is meant to test. A testcase is always written using the `greg-testcase' procedure.

helper procedures

The testing framework defines various helper procedures (in `begin.grg' and `Protocols.scm') that you should probably use as the basis for a new testsuite for a class.

You should start any testsuite for a class with `test-alloc' to check that basic operations work. Next you should define a few variables for test objects, assign instances of the class to them (inside a testcase), and pass them to the `test-NSObject' procedure to check that they conform to the NSObject protocol. Then, before writing your own specific tests, you might use other procedures to check conformance to other protocols.

The helper procedures defined in `begin.grg' are -

protocol checkers

greg-testcase

The `greg-testcase' procedure takes three arguments -

The Guile programming language permits the `thunk' to return in four ways -

As there are no other ways in which the `thunk' may be exited, it is impossible for a testcase to produce a result that doesn't fit into the framework (unless your testcase manages either to crash Guile or enter an infinite loop - in which case you won't get any output).

The value returned by the `greg-testcase' procedure is a boolean - `#t' if the test resulted in an expected pass, `#f' otherwise.
You can use this return value to make the execution of subsequent testcases dependent on the success of an earlier testcase.


;
; A testcase to check an instance of numeric addition
;
(greg-testcase "One plus One is two" #t
(lambda ()
  (eq? (+ 1 1 ) 2)
))

;
;  The above testcase will generate output -
;  'PASS: One plus One is two'
;


Go to the first, previous, next, last section, table of contents.