prompts/skills/clojure-test-check/SKILL.md
Property-based testing with clojure.test.check. Use when writing generative tests, creating custom generators, or debugging shrinking behavior. Triggers on test.check imports, prop/for-all, gen/* usage, or questions about property-based testing in Clojure.
npx skillsauth add ramblurr/nix-devenv clojure-test-checkInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Property-based testing generates random test data to verify properties hold across many inputs. Instead of specific test cases, define universal properties.
(require '[clojure.test.check :as tc]
'[clojure.test.check.generators :as gen]
'[clojure.test.check.properties :as prop])
(def my-property
(prop/for-all [v (gen/vector gen/small-integer)]
(= (count v) (count (reverse v)))))
(tc/quick-check 100 my-property)
;; => {:result true, :pass? true, :num-tests 100, ...}
(require '[clojure.test.check.clojure-test :refer [defspec]])
(defspec sort-is-idempotent ;; 100 optional iterations value here
(prop/for-all [v (gen/vector gen/small-integer)]
(= (sort v) (sort (sort v)))))
Important! Prefer NOT to supply an iterations, prefer the framework defaults
| Generator | Produces |
|-----------|----------|
| gen/small-integer | Integers bounded by size |
| gen/large-integer | Full range integers |
| gen/nat | Non-negative integers |
| gen/boolean | true/false |
| gen/string | Strings |
| gen/keyword | Keywords |
| (gen/vector g) | Vectors of g |
| (gen/tuple g1 g2) | Fixed heterogeneous vectors |
| (gen/elements coll) | Random element from coll |
| (gen/one-of [g1 g2]) | Choose generator randomly |
See references/cheatsheet.md for complete generator reference.
fmap - Transform generated values:
(gen/fmap sort (gen/vector gen/small-integer)) ; sorted vectors
(gen/fmap set (gen/vector gen/nat)) ; sets from vectors
such-that - Filter values (use sparingly, only for likely predicates):
(gen/such-that not-empty (gen/vector gen/boolean))
bind - Chain generators (value from first determines second):
(gen/bind (gen/not-empty (gen/vector gen/small-integer))
#(gen/tuple (gen/return %) (gen/elements %)))
let - Macro combining fmap/bind:
(gen/let [a gen/nat
b gen/nat]
{:sum (+ a b) :a a :b b})
(defrecord User [name id email])
(def user-gen
(gen/fmap (partial apply ->User)
(gen/tuple gen/string-alphanumeric
gen/nat
(gen/fmap #(str % "@example.com") gen/string-alphanumeric))))
(def json-like
(gen/recursive-gen
(fn [inner] (gen/one-of [(gen/list inner)
(gen/map gen/keyword inner)]))
(gen/one-of [gen/small-integer gen/boolean gen/string])))
When a test fails, test.check automatically shrinks to minimal failing case:
;; Fails on vectors containing 42
(tc/quick-check 100
(prop/for-all [v (gen/vector gen/small-integer)]
(not-any? #{42} v)))
;; :fail [[-35 -9 42 8 31 ...]] <- original failure
;; :shrunk {:smallest [[42]]} <- minimal case
Avoid gen/bind when gen/fmap suffices - bind hampers shrinking:
;; Bad: shrinks poorly
(gen/let [n (gen/fmap #(* 2 %) gen/nat)]
(gen/vector gen/large-integer n))
;; Good: shrinks well
(gen/fmap #(cond-> % (odd? (count %)) pop)
(gen/vector gen/large-integer))
Use gen/large-integer for real integer testing - small-integer/nat cap at ~200.
Run at least 100 tests - Size cycles through 0-199, fewer tests means poor coverage.
Don't use such-that for unlikely predicates - Will timeout. Use fmap to construct valid values instead.
See references/advanced.md for sizing/shrinking details.
Roundtrip: (= x (decode (encode x)))
Idempotence: (= (f x) (f (f x)))
Invariant preservation: (= (count v) (count (sort v)))
Commutativity: (= (f a b) (f b a))
Model comparison: (= (my-impl x) (reference-impl x))
See references/examples.md for generator recipes.
testing
Use this OCP when executing or preparing to execute commands that change a live or important system, service reloads/restarts, package changes, deployments, migrations, firewall/network/access changes, credential rotation, NixOS switch/test/boot/deploy, or incident mitigation. It guides safe operations with a persisted ledger for scope, preflight, baseline, rollback, validation, and evidence.
development
Create new agent skills with proper structure, progressive disclosure, and bundled resources. Use when user wants to create, write, or build a new skill.
documentation
Naming conventions for workflow documents in prompts/. Use when creating plans, PRDs, research reports, idea capture or other workflow documents. Triggers on (1) creating new planning documents, (2) naming PRDs or research reports, (3) questions about document organization in prompts/.
testing
Grilling session that challenges your plan against the existing domain model, sharpens terminology, and updates documentation (CONTEXT.md, ADRs) inline as decisions crystallise. Use when user wants to stress-test a plan against their project's language and documented decisions.