Skip to content

Commit 5d937c0

Browse files
committed
Add examples and justification
Mostly lifted from the `clojure.test` documentation I had added to the original Expectations documentation.
1 parent a76d052 commit 5d937c0

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.cpcache
2+
*.jar

README.md

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

33
A `clojure.test`-compatible version of the [classic Expectations testing library](https://clojure-expectations.github.io/).
44

5+
## What?
6+
7+
This library brings `expect`, `more`, `more-of`, etc from Expectations into the
8+
`clojure.test` world to be used instead of (or in addition to) the familiar `is`
9+
macro. You can either use `deftest` from `clojure.test`, or `defexpect` from
10+
this library to wrap your tests.
11+
12+
```clojure
13+
(ns my.cool.project-test
14+
(:require [clojure.test :refer [deftest is]]
15+
[expectations.clojure.test :refer :all]))
16+
17+
;; mix'n'match libraries:
18+
19+
(deftest mixed
20+
(is 2 (+ 1 1))
21+
(expect even? (+ 1 1)))
22+
23+
;; simple equality tests:
24+
25+
(defexpect equality
26+
(expect 1 (* 1 1))
27+
(expect "foo" (str "f" "oo")))
28+
29+
;; the expected outcome can be a regular expression:
30+
31+
(defexpect regex-1
32+
(expect #"foo" "It's foobar!"))
33+
34+
;; since that has only a single expectation, it can be written more succinctly:
35+
36+
(defexpect regex-2 #"foo" "It's foobar!")
37+
38+
;; the expected outcome can be an exception type:
39+
40+
(defexpect divide-by-zero ArithmeticException (/ 12 0))
41+
42+
;; the expected outcome can be a predicate:
43+
44+
(defexpect no-elements empty? (list))
45+
46+
;; the expected outcome can be a type:
47+
48+
(defexpect named String (name :foo))
49+
50+
;; if the actual value is a collection, the expected outcome can be an element or subset "in" that collection:
51+
52+
(defexpect collections
53+
(expect {:foo 1} (in {:foo 1 :cat 4}))
54+
(expect :foo (in #{:foo :bar}))
55+
(expect :foo (in [:bar :foo])))
56+
```
57+
58+
Just like `deftest`, the `defexpect` macro creates a function that contains the test\(s\). You can run each function individually:
59+
60+
```clojure
61+
user=> (equality)
62+
nil
63+
```
64+
65+
If the test passes, nothing is printed, and `nil` is returned. Let's look at a failing test:
66+
67+
```clojure
68+
user=> (defexpect inequality (* 2 21) (+ 13 13 13))
69+
#'user/inequality
70+
user=> (inequality)
71+
72+
FAIL in (inequality) (.../README.md:67)
73+
expected: (=? (* 2 21) (+ 13 13 13))
74+
actual: 39
75+
nil
76+
```
77+
78+
The output is produced by `clojure.test`'s standard reporting functionality.
79+
The `=?` operator is an extension to `clojure.test`'s `assert-expr` multimethod
80+
that allows for Expectations style of predicate-or-equality testing (based on
81+
whether the "expected" expression resolves to a function or some other value):
82+
83+
```clojure
84+
user=> (defexpect indivisible odd? (+ 1 1))
85+
#'user/indivisible
86+
user=> (indivisible)
87+
88+
FAIL in (indivisible) (.../README.md:83)
89+
expected: (=? odd? (+ 1 1))
90+
actual: (not (odd? 2))
91+
nil
92+
```
93+
94+
Here we see the predicate (`odd?`) being applied in the "actual" result from
95+
`clojure.test`.
96+
97+
`expectations.clojure.test` supports the following features from Expectations so far:
98+
* simple equality test
99+
* simple predicate test
100+
* class test -- see `named` above
101+
* exception test -- see `divide-by-zero` above
102+
* regex test -- see `regex-1` and `regex-2` above
103+
* `(expect expected-expr (from-each [a values] (actual-expr a)))`
104+
* `(expect expected-expr (in actual-expr))` -- see `collections` above
105+
* `(expect (more-of destructuring e1 a1 e2 a2 ...) actual-expr)`
106+
* `(expect (more-> e1 a1 e2 a2 ...) actual-expr)` -- where `actual-expr` is threaded into each `a1`, `a2`, ... expression
107+
* `(expect (more e1 e2 ...) actual-expr)`
108+
* `(expect expected-expr (side-effects [fn1 fn2 ...] actual-expr))`
109+
110+
Read [the Expectations documentation](https://clojure-expectations.github.io/)
111+
for more details of these features.
112+
113+
Tests defined with `defexpect` behave just like tests defined with `deftest` and
114+
all of the existing `clojure.test`-based tooling will work with them, including
115+
fixtures, test runners, and other libraries that patch `clojure.test` to improve
116+
its error reporting and other features.
117+
118+
## Why?
119+
120+
Given the streamlined simplicity of Expectations, you might wonder why you
121+
would want to migrate your Expectations test suite to `clojure.test`-style
122+
named tests? The short answer is **tooling**! Whilst Expectations has
123+
well-maintained, stable plugins for Leiningen and Boot, as well as an Emacs mode,
124+
the reality is that Clojure tooling is constantly evolving and most of those
125+
tools -- such as the excellent [https://cider.readthedocs.io/en/latest/](CIDER),
126+
[https://cursive-ide.com/](Cursive),
127+
and the more recent [https://atom.io/packages/proto-repl](ProtoREPL)
128+
and [Chlorine](https://atom.io/packages/chlorine) (both for Atom) --
129+
are going to focus on Clojure's built-in testing library first.
130+
Support for the original form of Expectations, using unnamed tests, is
131+
non-existent in Cursive, and can be problematic in other editors.
132+
133+
A whole ecosystem
134+
of tooling has grown up around `clojure.test` and to take advantage of
135+
that with Expectations, we either need to develop compatible extensions to each
136+
and every tool or we need Expectations to be compatible with `clojure.test`.
137+
138+
One of the big obstacles for that compatibility is that, by default, Expectations
139+
generates "random" function names for test code (the function names are based on the
140+
hashcode of the text form of the `expect` body), which means the test
141+
name changes whenever the text of the test changes. To address that, the new
142+
`expectations.clojure.test` namespace introduces named expectations via
143+
the `defexpect` macro (mimicking `clojure.test`'s `deftest`
144+
macro). Whilst this goes against the [https://clojure-expectations.github.io/odds-ends.html](Test Names
145+
philosophy) that Expectations was created with, it buys us a lot in terms of
146+
tooling support!
147+
5148
## Test & Development
6149

7150
To test, run `clj -A:test:runner`.
8151

152+
## TODO
153+
154+
Add tests(!) and more examples.
155+
9156
## License & Copyright
10157

11158
Copyright © 2018-2019 Sean Corfield, all rights reserved.

0 commit comments

Comments
 (0)