Skip to content

Commit c3249f8

Browse files
committed
middleware.test: gracefully handle exceptions thrown within fixtures
Fixes #719
1 parent 2587706 commit c3249f8

File tree

5 files changed

+54
-14
lines changed

5 files changed

+54
-14
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## master (unreleased)
44

5+
### Bugs fixed
6+
7+
* [#719](https://github.com/clojure-emacs/cider-nrepl/issues/719): `middleware.test`: gracefully handle exceptions thrown within fixtures.
8+
59
## 0.27.2 (2021-10-03)
610

711
### Bugs fixed

project.clj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,10 @@
158158
:exclude-namespaces [cider.nrepl.middleware.test-filter-tests]
159159
:ignored-faults {:unused-ret-vals-in-try {cider.nrepl.middleware.profile-test [{:line 25}]}
160160
;; This usage of `proxy` can't avoid reflection warnings given that the `proxy` construct dispatches based on name only:
161-
:reflection {cider.nrepl.middleware.out [{:line 54}
162-
{:line 56}
163-
{:line 58}
164-
{:line 60}
165-
{:line 62}
166-
{:line 64}]}
161+
:reflection {cider.nrepl.middleware.out [{:line 55}
162+
{:line 57}
163+
{:line 59}
164+
{:line 61}
165+
{:line 63}
166+
{:line 65}]}
167167
:suspicious-test {cider.nrepl.middleware.profile-test [{:line 25}]}}}}]})

src/cider/nrepl/middleware/test.clj

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@
6060
([^Exception e f]
6161
(stack-frame (st/directory-namespaces) e f))
6262
([namespaces ^Exception e f]
63-
(->> (map (partial st/analyze-frame namespaces) (.getStackTrace e))
64-
(filter #(= (:class %) (.getName (class f))))
65-
(first))))
63+
(when-let [class-name (some-> f class .getName)]
64+
(->> e
65+
.getStackTrace
66+
(map (partial st/analyze-frame namespaces))
67+
(filter #(= (:class %) class-name))
68+
first))))
6669

6770
(defn- print-object
6871
"Print `object` using pprint or a custom print-method, if available."
@@ -81,21 +84,27 @@
8184
for pretty-printing Spec failures. Remember to `flush` if doing so."
8285
identity)
8386

87+
(def ^:private fallback-var-name
88+
"The pseudo var name which will be used when no var name can be found
89+
for a given test report."
90+
::unknown)
91+
8492
(defn test-result
8593
"Transform the result of a test assertion. Append ns, var, assertion index,
8694
and 'testing' context. Retain any exception. Pretty-print expected/actual or
8795
use its `print-method`, if applicable."
8896
[ns v m]
8997
(let [{:keys [actual diffs expected fault]
9098
t :type} m
99+
v-name (or (:name (meta v)) fallback-var-name)
91100
c (when (seq test/*testing-contexts*) (test/testing-contexts-str))
92-
i (count (get-in (:results @current-report {}) [ns (:name (meta v))]))
101+
i (count (get-in (:results @current-report {}) [ns v-name]))
93102
gen-input (:gen-input @current-report)]
94103

95104
;; Errors outside assertions (faults) do not return an :expected value.
96105
;; Type :fail returns :actual value. Type :error returns :error and :line.
97106
(merge (dissoc m :expected :actual)
98-
{:ns ns, :var (:name (meta v)), :index i, :context c}
107+
{:ns ns, :var v-name, :index i, :context c}
99108
(when (and (#{:fail :error} t) (not fault))
100109
{:expected (print-object expected)})
101110
(when (and (#{:fail} t) gen-input)
@@ -106,7 +115,7 @@
106115
{:diffs (extensions/diffs-result diffs)})
107116
(when (#{:error} t)
108117
(let [e actual
109-
f (or (:test (meta v)) @v)] ; test fn or deref'ed fixture
118+
f (or (:test (meta v)) (some-> v deref))] ; test fn or deref'ed fixture
110119
(*test-error-handler* e)
111120
{:error e
112121
:line (:line (stack-frame e f))})))))
@@ -151,7 +160,8 @@
151160
#(-> %
152161
(update-in [:summary :test] inc)
153162
(update-in [:summary type] (fnil inc 0))
154-
(update-in [:results ns (:name (meta v))]
163+
(update-in [:results ns (or (:name (meta v))
164+
fallback-var-name)]
155165
(fnil conj [])
156166
(test-result ns v m))
157167
(assoc :gen-input nil)))))

test/clj/cider/nrepl/middleware/test_test.clj

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
{:op "test"
2323
:ns "cider.nrepl.middleware.test-filter-tests"
2424
:tests (map name tests)})]
25-
(is (= tests (keys (:cider.nrepl.middleware.test-filter-tests results)))))
25+
(is (= tests (keys (:cider.nrepl.middleware.test-filter-tests results))))
26+
true)
2627
[:a-puff-of-smoke-test]
2728
[:a-smokey-test]
2829
[:a-puff-of-smoke-test :a-smokey-test]
@@ -131,6 +132,21 @@
131132
(is ((set tests) :a-puff-of-smoke-test)
132133
"smoke test is still present without a filter"))))
133134

135+
(deftest handling-of-tests-with-throwing-fixtures
136+
(require 'cider.nrepl.middleware.test-with-throwing-fixtures)
137+
(testing "If a given deftest's fixture throw an exception, those are gracefully handled"
138+
(let [{{{[{:keys [error]}] :cider.nrepl.middleware.test/unknown} :cider.nrepl.middleware.test-with-throwing-fixtures} :results
139+
:keys [summary status]
140+
:as test-result}
141+
(session/message {:op "test"
142+
:ns "cider.nrepl.middleware.test-with-throwing-fixtures"})]
143+
(testing (pr-str test-result)
144+
(is (= error
145+
"clojure.lang.ExceptionInfo: I'm an exception inside a fixture! {:data 42}"))
146+
(is (= summary
147+
{:error 1, :fail 0, :ns 1, :pass 0, :test 0, :var 0}))
148+
(is (= status #{"done"}))))))
149+
134150
(deftest run-test-with-map-as-documentation-message
135151
(testing "documentation message map is returned as string"
136152
(let [{:keys [results] :as test-result}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
(ns cider.nrepl.middleware.test-with-throwing-fixtures
2+
(:require
3+
[clojure.test :refer [deftest is use-fixtures]]))
4+
5+
(use-fixtures :once (fn [t]
6+
(throw (ex-info "I'm an exception inside a fixture!" {:data 42}))
7+
(t)))
8+
9+
(deftest foo
10+
(is (= 42 (* 21 2))))

0 commit comments

Comments
 (0)