Turn your comments into test

As a Clojure programmer you are probably used to evaluate code manually within comment expressions, Rich comments.

This is very similar to writing in a repl, but you select and evaluate an expression in the source code file rather than writing the expression up front. These expressions are hidden behind comments since they are expressions to interact with, rather than being part of the system. This is a very popular development technique in lisps, like Clojure.

You have comments like this in the source files:

(comment
  (def a 2)
  (+ a 3))

Var a becomes defined in the namespace when you evaluate these statements manually, rather than when you run the system, as it is embedded in a comment. Traditional example based tests, using e.g. clojure.test, are normally defined as functions, rather than as the result of interactive fiddling. Interactive fiddling and structured functions does not yield the same code structure and it is a bit of a hassle to restructure. Larger tests, involving more than individual units, do usually get incomprehensible while defined as single functions, which makes scripts more preferable.

It’s also likely that you use comment expressions to do some administrative tasks, like poking in a database or similar, that you probably don’t want automated, but keep as interactive snippets, close to related code.

I made this tool Testify, that automates execution of these kind of comments. It does not run your already existing comments as that would be very awkward and dangerous. Instead it evaluates a special test-comment, or some other comment like structure you prefer.

(ns project.testcase
  (:require [testify :refer [test-comment eval-in-ns]]))

;; Test comments are just like comments, macros that ignore body
(test-comment
  (def a 2)
  (+ a 3))

(comment
  ;; space for more experimental and administrative tasks,
  ;; like e.g. evaluating test-comments
  (eval-in-ns 'project.testcase))

If you which you can run these test-comments from ordinary test cases:

(ns project.testcase
  (:require [testify :refer [test-comment eval-as-use]]
            [clojure.test :refer [deftest is]]))

(test-comment
  (def a 2)
  (+ a 3)
  (is (= 5 *1)))

;; A unit test is better evaluated with eval-as-use
;; since it uses a temporary namespace to prevent
;; altering the target. (def a 2) above is placed
;; in an anonymous temporary namespace.

(deftest test-the-test
  (eval-as-use 'project.testcase))

Running the test, an ordinary clojure.test will print the evaluation to *out*, as it if was evaluated in a repl.

(clojure.core/in-ns 'project.testcase-9379)
=> #namespace[project.testcase-9379]

(clojure.core/use 'clojure.core)
=> nil

(clojure.core/require
 '[testify :refer [test-comment eval-as-use]]
 '[clojure.test :refer [deftest is]])
=> nil

(clojure.core/use 'project.testcase)
=> nil

(def a 2)
=> #'project.testcase-9379/a

(+ a 3)
=> 5

(is (= 5 *1))
=> true

(clojure.core/remove-ns 'project.testcase-9379)
=> #namespace[project.testcase-9379]

This only works for Clojure on the JVM at the moment.
It is called Testify


All #art #clojure #csharp #data-structures #database #datomic #emacs #fortran #fsharp #functional #haskell #history #immutability #java #jit #jmm #lambdas #lisp #pioneers #poetry #programming #programming-philosophy #randomness #rant #reducers #repl #smalltalk #sql #threads #women