Liking cljdoc? Tell your friends :D

Testing

See Testing Strategy for the conceptual overview. This guide covers the day-to-day commands and patterns.

Test commands

# All tests
clojure -M:test:test/all

# Single library
clojure -M:test :core
clojure -M:test :user

# By tag
clojure -M:test:test/all --focus-meta :unit
clojure -M:test:test/all --focus-meta :integration
clojure -M:test:test/all --focus-meta :contract

# Single namespace
clojure -M:test:test/all --focus user-property-test

# Watch mode
clojure -M:test --watch :core
clojure -M:test:test/all --watch --focus-meta :unit

# Auth tests (JWT secret required)
JWT_SECRET="dev-secret-at-least-32-characters-long" clojure -M:test :user

Writing unit tests

Tag with ^:unit. Call core functions directly - no setup needed:

(ns wagoe.product.core.product-test
  (:require [clojure.test :refer [deftest is testing]]
            [wagoe.product.core.product :as product-core]))

(deftest ^:unit test-prepare-product
  (testing "returns a product with a generated id"
    (let [now    (java.time.Instant/now)
          result (product-core/prepare-product {:name "Widget" :price 9.99M} now)]
      (is (uuid? (:id result)))
      (is (= "Widget" (:name result)))
      (is (= 9.99M (:price result)))))

  (testing "adds timestamps"
    (let [now    (java.time.Instant/now)
          result (product-core/prepare-product {:name "Widget" :price 9.99M} now)]
      (is (inst? (:created-at result)))
      (is (inst? (:updated-at result))))))

Writing integration tests

Tag with ^:integration. Use in-memory adapters to test service orchestration:

(ns wagoe.product.shell.service-test
  (:require [clojure.test :refer [deftest is use-fixtures]]
            [wagoe.product.shell.service :as service]
            [wagoe.product.shell.adapters.in-memory :as mem]))

(defn with-service [f]
  (let [repo (mem/create-in-memory-repo)]
    (binding [*service* (service/create-product-service {:repo repo})]
      (f))))

(use-fixtures :each with-service)

(deftest ^:integration test-create-product
  (let [result (service/create-product *service* {:name "Widget" :price 9.99M})]
    (is (= "Widget" (:name result)))
    (is (uuid? (:id result)))))

Writing contract tests

Tag with ^:contract. Test against a real H2 in-memory database:

(ns wagoe.product.shell.persistence-test
  (:require [clojure.test :refer [deftest is use-fixtures]]
            [wagoe.product.shell.persistence :as persistence]
            [wagoe.test.fixtures :as fixtures]))

(use-fixtures :each fixtures/with-database)

(deftest ^:contract test-round-trip
  (let [product {:id (random-uuid) :name "Widget" :price 9.99M
                 :created-at (java.time.Instant/now)}
        _       (persistence/create-product! db product)
        found   (persistence/find-product-by-id db (:id product))]
    (is (= (:name product) (:name found)))
    (is (= (:price product) (:price found)))))

Test suite in tests.edn

Add new libraries to tests.edn:

{:kaocha/tests
 [;; existing suites ...
  {:kaocha.testable/id :product
   :kaocha/source-paths ["libs/product/src"]
   :kaocha/test-paths   ["libs/product/test"]
   :kaocha/ns-patterns  ["wagoe.product.*-test"]}]}

AI test generation

bb ai gen-tests src/<your-project>/product/core/product.clj

Generates a complete test namespace from the source file using Wagoe conventions. The model sees the real protocols and vars of every namespace the source requires. The answer is linted as bb check lints it, never run, and retried once with the errors; if it still fails nothing is written unless you pass --force. Each deftest is tagged ^:unit unless it does real I/O.

Can you improve this documentation? These fine people already did:
Thijs Creemers & thijscreemers
Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close