Skip to content
You wrote fdefs. But how are you going to test them?
Clojure Shell
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci
script
src/respeced
test/respeced
.gitignore
CHANGELOG.md
LICENSE
README.md
deps.edn
project.clj

README.md

respeced

CircleCI Clojars Project cljdoc badge

Rationale

This library helps verify that spec fdefs do what they are supposed to do:

  • throw errors on non-valid arguments and return values
  • not throw on valid arguments and return values

A good illustration of the intended usage of this library can be seen in tests for the speculative library, where this library originated from.

Respeced fully supports Clojure, ClojureScript and self-hosted ClojureScript.

Installation

tools.deps.alpha

respeced {:mvn/version "0.0.1"}

leiningen

[respeced "0.0.1"]

API

with-instrumentation

Instrument a function in the scope of a body. Restores instrumentation state, i.e. unstruments after the call only when the function was not instrumented before the call).

Example call:

(with-instrumentation `foo (foo 1 2 3))

with-unstrumentation

Unstrument a function in the scope of a body. Restores instrumentation state, i.e. only re-instruments after the call when the function was instrumented before the call.

Example call:

(with-unstrumentation `foo (foo 1 2 3))

caught?

Returns true if body throws spec error for instrumented fn.

Example call:

(deftest my-fdef-works
  (with-instrumentation `foo
    (is (caught? `foo (foo :some-wrong-argument))))

check-call

Applies args to function resolved by symbol. Checks :args, :ret and :fn specs. Returns return value of call if succeeded, else throws.

Example call:

(is (= [4 5 6] (check-call `foo [1 2 3])))

check

Like clojure.spec.test.alpha/check with third arg for passing clojure.test.check options.

Example call:

(check `foo {} {:num-tests 10})

successful?

Returns true if all clojure.spec.test.alpha/check tests have pass? true.

Example call:

(successful? (check `foo {} {:num-tests 10}))

Example usage

$ clj -Sdeps '{:deps {respeced {:mvn/version "0.0.1"}}}'
Clojure 1.10

user=> (require '[respeced.test :as rt])
nil

user=> (require '[clojure.spec.alpha :as s])
nil

user=> (s/fdef foo :args (s/cat :n number?) :ret number?)
user/foo

;; this function has the wrong return value according to the spec:

user=> (defn foo [n] "ret")
#'user/foo

;; rt/check-call helps with checking `:ret` and `:fn` specs:

user=> (rt/check-call `foo [1])
Execution error - invalid arguments to respeced.test$do_check_call/invokeStatic at (test.cljc:138).
"ret" - failed: number? at: [:ret]

;; change the spec:

user=> (s/fdef foo :args (s/cat :n number?) :ret string?)
user/foo

;; no error anymore:

user=> (rt/check-call `foo [1])
"ret"

;; instrument a function within a scope:

user=> (rt/with-instrumentation `foo (foo "a"))
Execution error - invalid arguments to user/foo at (REPL:1).
"a" - failed: number? at: [:n]

;; not instrumented:

user=> (foo "a")
"ret"

;; `rt/check` has a third arg for passing `clojure.test.check` options:

user=> (rt/check `foo nil {:num-tests 1})
generatively testing user/foo
({:spec #object[clojure.spec.alpha$fspec_impl$reify__2524 0x72bd06ca "clojure.spec.alpha$fspec_impl$reify__2524@72bd06ca"], :clojure.spec.test.check/ret {:result true, :pass? true, :num-tests 1, :time-elapsed-ms 1, :seed 1541249961647}, :sym user/foo})

;; validate if generative test was successful:

user=> (rt/successful? *1)
true

user=>

Tests

Clojure

clj -A:test:clj-tests

ClojureScript

script/cljs-tests

Self-Hosted ClojureScript

plk -A:test:plk-tests

License

Copyright © 2018 Michiel Borkent

Distributed under the EPL License, same as Clojure. See LICENSE.

You can’t perform that action at this time.