Skip to content

Commit 8439983

Browse files
committed
Expand the Testing section with practical guidelines
Add six new rules: use testing blocks for context, informative assertion messages, are for tabular tests, one concept per deftest, use with-redefs sparingly, and test expected exceptions. Brings the section from 3 to 9 rules.
1 parent 07bc1c9 commit 8439983

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

README.adoc

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3412,6 +3412,105 @@ with `deftest` and name them `something-test`.
34123412
(deftest something ...)
34133413
----
34143414

3415+
=== Use `testing` Blocks for Context [[use-testing-blocks]]
3416+
3417+
Group related assertions under `testing` to provide context in
3418+
failure output. This makes it clear which scenario failed without
3419+
having to read the assertion itself.
3420+
3421+
[source,clojure]
3422+
----
3423+
;; good
3424+
(deftest user-validation-test
3425+
(testing "rejects blank names"
3426+
(is (not (valid? {:name ""}))))
3427+
(testing "accepts valid names"
3428+
(is (valid? {:name "Bruce"}))))
3429+
3430+
;; bad - no context when an assertion fails
3431+
(deftest user-validation-test
3432+
(is (not (valid? {:name ""})))
3433+
(is (valid? {:name "Bruce"})))
3434+
----
3435+
3436+
=== Prefer Informative Assertion Messages [[informative-assertion-messages]]
3437+
3438+
Add messages to `is` when the assertion alone doesn't explain the
3439+
failure.
3440+
3441+
[source,clojure]
3442+
----
3443+
;; good - the failure message explains what went wrong
3444+
(is (= 200 (:status response)) "Expected HTTP 200 for valid input")
3445+
3446+
;; ok - obvious assertions don't need a message
3447+
(is (true? (even? 4)))
3448+
----
3449+
3450+
=== Use `are` for Tabular Tests [[use-are-for-tabular-tests]]
3451+
3452+
When testing the same logic with many inputs, prefer `are` over
3453+
repetitive `is` forms.
3454+
3455+
[source,clojure]
3456+
----
3457+
;; good
3458+
(deftest palindrome?-test
3459+
(are [s expected] (= expected (palindrome? s))
3460+
"racecar" true
3461+
"hello" false
3462+
"madam" true
3463+
"" true))
3464+
3465+
;; bad - repetitive
3466+
(deftest palindrome?-test
3467+
(is (true? (palindrome? "racecar")))
3468+
(is (false? (palindrome? "hello")))
3469+
(is (true? (palindrome? "madam")))
3470+
(is (true? (palindrome? ""))))
3471+
----
3472+
3473+
=== Test One Concept per `deftest` [[one-concept-per-deftest]]
3474+
3475+
Each `deftest` should cover one logical behavior. Use `testing`
3476+
blocks for sub-cases rather than separate `deftest` forms for every
3477+
edge case.
3478+
3479+
=== Use `with-redefs` Sparingly [[use-with-redefs-sparingly]]
3480+
3481+
Use `with-redefs` only for external boundaries (HTTP, database,
3482+
clock). Prefer designing functions to take dependencies as arguments
3483+
instead.
3484+
3485+
[source,clojure]
3486+
----
3487+
;; good - inject the dependency
3488+
(defn fetch-users [http-get]
3489+
(http-get "/api/users"))
3490+
3491+
(deftest fetch-users-test
3492+
(is (= [{:name "Bruce"}]
3493+
(fetch-users (constantly [{:name "Bruce"}])))))
3494+
3495+
;; ok for integration-level tests
3496+
(deftest fetch-users-integration-test
3497+
(with-redefs [http/get (constantly {:body [{:name "Bruce"}]})]
3498+
(is (= [{:name "Bruce"}] (fetch-users)))))
3499+
----
3500+
3501+
=== Test Expected Exceptions [[test-expected-exceptions]]
3502+
3503+
Use `thrown?` and `thrown-with-msg?` to assert that code raises the
3504+
expected exception.
3505+
3506+
[source,clojure]
3507+
----
3508+
;; good
3509+
(deftest division-test
3510+
(is (thrown? ArithmeticException (/ 1 0)))
3511+
(is (thrown-with-msg? ExceptionInfo #"Invalid" (validate! nil))))
3512+
----
3513+
34153514
== Library Organization
34163515

34173516
=== Library Coordinates [[lib-coordinates]]

0 commit comments

Comments
 (0)