the little racketeer – 04

As noted in the first post in this series, the little schemer uses three procedures that are not in the racket spec (or scheme spec), atom?, add1, and sub1. This is the chapter that introduces the latter two procedures, which take one argument return the argument incremented or decremented respectively, and then use the structure introduced in the previous three chapters to deal with numeric operations.

The authors update the first and fourth “commandments” to recommend using the zero? question (instead of null?) to find the termination condition when recurring through a number. They also bring in mathematical identities for the terminating values (zero for addition, one for multiplication).

They also introduce recurring over two lists or two numbers simultaneously.

The most interesting part of this chapter is the construction of recursive comparative functions for greater-than, less-than, and equal-to, by recurring through two numbers and consider which one reaches zero first. The ordering of the zero? tests matters, and can have you easily writing a greater-than-or-equal-to procedure instead of greater-than.

It was while reading this chapter that I decided to learn how to do unit testing more systematically. The motivation is that I wanted to write the tests before the implementation, and separating tests from implementation let you do that without getting name errors for trying to reference a procedures before they are defined. So I split my “test” logic into a separate file, and then found RackUnit.

Racket ships with RackUnit. RackUnit tests can be run from the command line with raco test or from within emacs. So, here’s a quickstart to getting some tests running.

First, you’ll have to use the provide keyword to make the procedures you want to test visible to other modules.

(provide procedure1 procedure2 ... procedureN)

Now, make a new racket file, and import rackunit and your source module.

(require rackunit "source-file.rkt")

One basic test is check-equal? which has three arguments: two S-expressions to compare and a message. The text works us through creating a recursive replacement for the expt function. I made some tests for this procedure based on the text and added a test case for 0 to be sure that x^0 = 1:

(check-equal? (expt 10 0) 1 "expt: 10^0 == 1")

Other basic checks are check-eq? and check-eqv?, and each of these three checks has a negative check: check-not-eq?, check-not-equal? and check-not-eqv?.

You can run this in a terminal with:

> raco test test.rkt

To run your tests in emacs, you have to wrap your tests in a submodule:

(module+ test
  (tests...))

You can then run these tests with C-c C-t, which will open a Racket-REPL buffer and run the tests in your test submodule. The return will be empty if all tests pass. You can also use raco to run those tests which will open a shell buffer and run raco test on your test submodule.

RackUnit docs

raco test docs

emacs racket-mode docs