-
Notifications
You must be signed in to change notification settings - Fork 2
/
templating.html
162 lines (145 loc) · 8.38 KB
/
templating.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Expectations by jaycfields</title>
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<script src="javascripts/scale.fix.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1 class="header">Expectations</h1>
<p class="header">a minimalist's unit testing framework</p>
<ul>
<li><a class="buttons" href="index.html">Home</a></li>
<li><a class="buttons" href="installing.html">Installing</a></li>
<li><a class="buttons" href="introduction.html">Introduction</a></li>
<li><a class="buttons" href="advanced.html">Advanced</a></li>
<li><a class="buttons" href="collections.html">Collections</a></li>
<li><a class="buttons" href="templating.html">Expect More</a></li>
<li><a class="buttons" href="odds-ends.html">Odds & Ends</a></li>
<li><a class="buttons" href="in-context.html">Around Each</a></li>
<li><a class="buttons" href="before-run-hook.html">Around Suite</a></li>
<li><a class="buttons" href="state-warnings.html">State Warnings</a></li>
<li><a class="buttons" href="redef-state.html">Redef State</a></li>
<li><a class="buttons" href="interactions.html">Side Effects</a></li>
<li><a class="buttons" href="freeze-time.html">Freeze Time</a></li>
<li><a class="buttons" href="env-tweaks.html">ENV Tweaks</a></li>
<li><a class="buttons" href="emacs-tweaks.html">emacs Tweaks</a></li>
<li><a class="buttons" href="clojure-test.html">clojure.test</a></li>
<li><a class="buttons github" href="https://github.com/clojure-expectations/expectations">View On GitHub</a></li>
</ul>
<p class="header">This project is maintained by <a class="header name" href="https://github.com/seancorfield">seancorfield</a> and <a class="header name" href="https://github.com/jaycfields">jaycfields</a></p>
</header>
<section>
<h1>
<a name="expectations" class="anchor" href="#expectations"><span class="octicon octicon-link"></span></a>expectations</h1>
<blockquote>
<p>adding signal, removing noise</p>
</blockquote>
<h2>
<a name="templating" class="anchor" href="#templating"><span class="octicon octicon-link"></span></a>Expecting More</h2>
<a href="https://github.com/clojure-expectations/expectations">expectations</a> obviously has a bias towards <a href="http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html">one assertion per test</a>; however, there are times that verifying several things at the same time does make sense. For example, if you want to verify a few different properties of the same Java object it probably makes sense to make multiple assertions on the same instance.<br />
<br />
One of the biggest problems with multiple assertions per test is when your test follows this pattern:<br />
<ol>
<li>create some state</li>
<li>verify a bit about the state</li>
<li>alter the state</li>
<li>verify more about the state</li>
</ol>
Part of the problem is that the assertions that occurred before the altering of the state may or may not be relevant after the alteration. Additionally, if any of the assertions fail you have to stop running the entire test - thus some of your assertions will not be run (and you'll be lacking some information).
<h4>more, more->, & more-of</h4>
expectations takes an alternate route - embracing the idea of multiple assertions by providing a specific syntax that allows multiple verifications and the least amount of duplication.
<br><br>
expectations has always given you the ability to test against an arbitrary fn, similar to the example below.
<br><br>
<pre>(expect nil? nil)</pre>
The ability to specify any fn is powerful, but it doesn't always give you the most descriptive failure messages.
In expectations 2.0 we introduce the 'more, 'more->, & 'more-of macros, which are designed to allow you to expect
more of your actual values.
<br><br>
Below is a simple example of using the more macro.
<br><br>
<pre>(expect (more vector? not-empty) [1 2 3])</pre>
As you can see from the above example, we're simply expecting that the actual value '[1 2 3] is both a 'vector? and 'not-empty.
The 'more macro is great when you want to test a few 1 arg fns; however, I expect you'll more often find yourself reaching for
'more-> and 'more-of.
<br><br>
The 'more-> macro is used for threading the actual value and comparing the result to an expected value. Below is a simple
example of using 'more to pull values out of a vector and test their equality.
<br><br>
<pre>(expect (more-> 1 first
3 last)
[1 2 3])</pre>
The 'more-> macro threads using -> (thread-first), so you're able to put any form you'd like in the actual transformation.
<br><br>
<pre>(expect (more-> 2 (-> first (+ 1))
3 last)
[1 2 3])</pre>
Finally, 'more-> can be very helpful for testing various kv pairs within a map, or various Java fields.
<br><br><pre>(expect (more-> 0 .size
true .isEmpty)
(java.util.ArrayList.))
(expect (more-> 2 :a
4 :b)
{:a 2 :b 4})</pre>
Threading is great work, if you can get it. For the times when you need to name your actual value, 'more-of should do the trick. The following example demonstrates how to name your actual value and then specify a few expectations.
<br><br><pre>(expect (more-of x
vector? x
1 (first x))
[1 2 3])</pre>
If you've ever found yourself wishing you had destructuring in clojure.test/are or expectations/given, you're not alone. The good news is, 'more-of supports any destructuring you want to give it.
<br><br><pre>(expect (more-of [x :as all]
vector? all
1 x)
[1 2 3])</pre>
<h4>from-each</h4>
It's common to expect something from a list of actual values. Traditionally 'given was used to generate many tests from one form. Unfortunately 'given suffered from many issues: no ability to destructure values, failure line numbers were almost completely useless, and little visibility into what the problem was when a failure did occur.
<br><br>
In expectations 2.0 'from-each was introduced to provide a more powerful syntax as well as more helpful failure messages.
<br><br>
Below you can see a very simple expectation that verifies each of the elements of a vector is a String.
<br><br><pre>(expect String
(from-each [letter ["a" "b" "c"]]
letter))</pre>
Hopefully the syntax of 'from-each feels very familiar, it's been written to handle the same options as 'for and 'doseq - :let and :when.
<br><br>
<pre>(expect odd? (from-each [num [1 2 3]
:when (not= num 2)]
num))
(expect odd? (from-each [num [1 2 3]
:when (not= num 2)
:let [numinc1 (inc num)]]
(inc numinc1)))</pre>
While 'from-each is helpful in creating concise tests, I actually find it's most value when a test fails. If you take the above test and remove the :when, you would have the test below.
<br><br><pre>(expect odd? (from-each [num [1 2 3]
:let [numinc1 (inc num)]]
(inc numinc1)))</pre>
The above test would definitely fail, but it's not immediately obvious what the issue is. However, the failure message should quickly lead you to the underlying issue.
<br><br><pre>
failure in (success_examples.clj:206) : success.success-examples
(expect
odd?
(from-each [num [1 2 3] :let [numinc1 (inc num)]] (inc numinc1)))
the list: (3 4 5)
(expect odd? (inc numinc1))
locals num: 2
numinc1: 3
4 is not odd?</pre>
As you can see above, when 'from-each fails it will give you values of every var defined within the 'from-each bindings. As a result, it's fairly easy to find the combination of vars that led to a failing test.
</section>
<footer>
<p><small>Hosted on <a href="https://pages.github.com">GitHub Pages</a> using the Dinky theme</small></p>
</footer>
</div>
<!--[if !IE]><script>fixScale(document);</script><![endif]-->
</body>
</html>