Home Blog Contact
fil RSSRSS Flux

Recent entries

Archives

Mocking for your Scheme Unit Test

Unit Testing is useful for testing your code. At the heart of a unit test are your assetions that check your code. Here is an example.


(define-unit-test check

  (assert (string=? (string-upcase "Hello world") "HELLO WORLD")))

The assert macro performs the test and reports any problems encountered. This kind of tests goes a long way and allow you to have a nice test suite for your code.

Now let say that you have a web application. For the login process you also have a password reset procedure that resets the password and sends a mail containing the new password to the user. Here is how such a procedure could be implemented.


(define (reset-password-for-user user-name)

  (with-db *db*

    (lambda ()

      (let ((user (find-user-by-name user-name))

            (new-password (random-password)))

        (set-user-password! user new-password)

        (send-mail (user-email user) (string-append "Your new password is:" new-password))))))

You want your unit test to verify that the mail is really sent when you reset a password. What we are going to do is to mock the send-mail procedure. Mocking a procedure consists in modifying the original procedure such that calling it is recorded in the system. Later your unit test will check that a record exists.

So let define the mocking framework.


(define (mock procedure)

  (lambda args

    (record-procedure-call! procedure args)

    (apply procedure args)))



(define-syntax mock!

  (syntax-rules ()

    ((mock! procedure-name)

     (set! procedure-name (mock procedure-name)))))

To mock a procedure you call (mock! <your-procedure>). The mock macro registers a procedure to be mocked.

The second step for your unit test is the check definition for ensuring that the code behave correctly. Let's define some check procedures.


(define (assert-that-procedure-was-called-n-times procedure n)

  (= (length (procedure-called procedure)) n))

Finally you can define your unit test in the following way.


(define-unit-test mock

  "Check that a mail is sent to the user when we reset the password for a user"

  (mock! send-mail)

  (reset-password-for-user "pierre")

  (assert-that-procedure-was-called-n-times send-mail 1))

A good mock framework provides many more kinds of assertion related to procedure calling. For example instead of simply making sure that the procedure send-mail is called, we could ensure that the parameters are right. Your imagination is the limit here.

Comments

Add a comment

Name: required
URL: (optional)
Mail: required (will never be shown)
81+3= basic human verification