Liking cljdoc? Tell your friends :D

clj-by-example

Self-testing examples in your clojure code.

Clojars Project

Motivation

The usual workflow for clojure code is to write the functional code under src/ and the unit tests under test/. While it is an advisable thing to separate the two, I think it is useful to keep a subset of the tests directly below the function and macro definitions, as examples.

There are two main benefits:

  • it is easier to mix coding & testing interactively

  • the examples contribute to the code documentation, showing examples of uses just below the definitions.

It is also a way to provide a lean support for literate programming, although some further processing is needed.

Usage

The library provides two macros: example and do-for-example.


clj-by.example/example
([expr sep val & {:keys [equiv?], :or {equiv? =}}])

Show as an example the evaluation of expr as val. Evaluate the example as a test an throw an exception if it fails, if a variable +examples-enabled+ is set and bound to a truthy value.


clj-by.example/do-for-example
([& body])

A do-like construct only compiled if a variable +examples-enabled+ is bound in the current namespace. This is used to prepare examples with some variable or function definitions.

Example

Suppose you have a file funtastic.clj that needs some coding.

;;; file funtastic.clj
(ns super-tool.funtastic
  (:require 'clj-by.example :refer [example do-for-example]))
;; define this to a truthy value for self-testing examples,
;; otherwise ... don't
(def ^:private +examples-enabled+ true)

You first want to code the most boring function.

(defn fact
  "Return a boring result."
  [n] (if (zero? n)
          1
          (* n (fact (- n 1)))))

Then you add some examples:

(example (fact 0) => 1) ;; returns 1

(example (fact 5) => 120)  ;; return 120

If you want to have some definitions ready for your examples, use the do-for-example macro...

(do-for-example
  (def my-example-var 6))

Then the variable my-example-var is available for your tests (and also outside the tests, please be careful).

(example (fact my-example-var) => 600) ;; return 600

Finally, the self-testing examples throw an exception in case of failure, this is a fail-first strategy and thus it is a complement and not a replacement for standard unit testing.

(example (fact 3) => 1)
;; throws ExceptionInfo Example failed  clojure.core/ex-info
;;     Example failed
;;     {:val 6, :expr (fact 3), :expected 1}

Disable self-testing

If in your namespace you do not define +examples-enabled+ or set it to a falsy value, then the self-testing mode is disabled.

;; define this to a truthy value for self-testing examples,
;; otherwise ... don't
(def ^:private +examples-enabled+ false) ;; remark: false!

...

(example (fact 0) => 1) ;; return nil

(example (fact 5) => 120)  ;; return nil

If you want to have some definitions ready for your examples, use the do-for-example macro...

(do-for-example
  (def my-example-var 6)) ;; nothing defined, returns nil

...

(example (fact my-example-var) => 600) ;; return nil

...

(example (fact 3) => 1) ;; return nil

License

Copyright © 2015 Frederic Peschanski under the MIT License

Can you improve this documentation? These fine people already did:
Fredokun & Frederic Peschanski
Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close