RCT turns rich comment forms into tests.
^:rct/test
(comment
(+ 1 1) ;=> 2
(+ 1 1) ;=> 3
)
(com.mjdowney.rich-comment-tests/run-ns-tests! *ns*)
; Testing com.mjdowney.rich-comment-tests.example
;
; FAIL in () (example.clj:4)
; expected: (= (+ 1 1) 3)
; actual: (not (= 2 3))
;
; Ran 1 tests containing 2 assertions.
; 1 failures, 0 errors.
;=> {:test 1, :pass 1, :fail 1, :error 0}
CHANGELOG | Uses Break Versioning
io.github.robertluo/rich-comment-tests #:git{:sha "22ea82d321b99f659f18c5b8822859292bd1026cn"}
RCT is a version of the excellent hyperfiddle/rcf
that uses rewrite-clj
to evaluate comment
blocks and match the result of each sexpr against
;=> result
comments.
It was inspired by the discussion in hyperfiddle/rcf/issues/49. Further discussion / feature requests welcome.
Its goals are to encourage writing rich comment forms in the most natural
way possible, using normal (comment ...)
forms and Clojure comments, and to
integrate nicely with both REPL and clojure.test workflows.
Non-goals include providing advanced unit test features and syntax (the
original hyperfiddle/rcf is much better for this!) or completely replacing
clojure.test. I see this as a complementary tool to aid in REPL development,
help keep examples from comment
forms up to date with CI, and encourage
writing small tests alongside the function under test.
comment
forms as you normally would, and tag some of them with
{:rct/test true}
.run-ns-tests!
to the REPL (I
have an editor shortcut that reloads the namespace and then does this).RCT supports three kinds of assertions:
=>
asserts literal equality=>>
asserts a matcho pattern
(and allows ... to indicate a partial pattern)throws=>>
asserts an exception expected, the thrown exception (Throwable) will turns into a error record, like {:error/class Exception, :error/message "this is an error", :error/cause #{another...} :error/data {:some 'data}}
, an example:
(throw (ex-info "ok" {:number 3})) ;throws=>> #:error{:message #".." :data {:number odd?}}
Assertions are either part of the comment or follow it directly.
RCT treats a symbol directly followed by =>
or =>>
as an assertion operator. To make a new assertion operator, refer to emit-tests/emit-assertion
multimethod.
^:rct/test
(comment
;; Literal assertions with =>
(range 3) ;=> (0 1 2)
(+ 5 5) ;; => 10
(System/getProperty "java.version.date") ;=> "2022-09-20"
;; Pattern matching assertions with =>>
(range 3) ;=>> '(0 1 ...)
(+ 5 5) ;=>> int?
(into {} (System/getProperties))
;=>> {"java.version.date" #"\d{4}-\d{2}-\d{2}"}
(def response {:status 200 :body "ok"})
response
;=>> {:status #(< % 300)
; :body not-empty}
;; Or with spec
(require '[clojure.spec.alpha :as s])
(into {} (System/getProperties)) ;=>> (s/map-of string? string?)
;; Or using a blank ;=> line to match against the next form
response
;=>
{:status 200
:body "ok"}
)
RCT is designed to hook in nicely with clojure.test
reporting / assertion
counting, and to be easy to run from an idiomatic Clojure CI workflow.
deftest
to run all rich comment tests in the source treeThis works well for the following scenario:
test/
directory with source files that use clojure.test
+ deftest
,src
directory with rich comment tests sprinkled throughout,(ns some-test-ns
(:require [clojure.test :refer :all]
[com.mjdowney.rich-comment-tests.test-runner :as test-runner]))
(deftest rct-tests
(test-runner/run-tests-in-file-tree! :dirs #{"src"}))
Now when you run clojure.test
, rich comment tests are also included.
This is what happens when you run this project with:
clj -X:test
For a project that only uses rich comment tests, you can add an alias to
deps.edn
:
{:aliases
{:test {:exec-fn com.mjdowney.rich-comment-tests.test-runner/run-tests-in-file-tree!
:exec-args {:dirs #{"src"}}}}}
Sample bb.edn file to run RCTs via bb test
:
{:paths ["src"]
:deps {}
:tasks {test
{:docs "Run unit tests."
:extra-deps {io.github.matthewdowney/rich-comment-tests {...}}
:requires ([com.mjdowney.rich-comment-tests.test-runner :as rct])
:task (rct/run-tests-in-file-tree! {:dirs #{"src"}})}}}
See also: Running tests from the Babashka book.
This fork
throws=>>
operator to catch expected Throwable
(Exceptions).=>
form to match the (is (= .. ..))
concept.v1.0.2 (2023-02-09)
v1.0.1 (2023-02-07)
v1.0.0 — no breaking changes, API is now stable 🎉 (2023-01-21)
v0.0.4 (2023-01-04)
v0.0.3 (2022-12-11)
;=>>
#2v0.0.2 (2022-12-07)
clojure.test
reporting + way to run RCT alongside itv0.0.1 (2022-12-06)
Can you improve this documentation? These fine people already did:
Matthew Downey & Luo TianEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close