-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhamcrest_matchers.html
260 lines (252 loc) · 12.3 KB
/
hamcrest_matchers.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8" />
<title>Hamcrest matchers</title>
<meta name="description" content="" />
<meta name="author" content="Vidar Johansen" />
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<link type="text/css" rel="stylesheet" href="css/SyntaxHighlighter.css">
<link type="text/css" rel="stylesheet" href="css/styles.css">
<script src="js/shCore.js"></script>
<script src="js/shBrushJava.js"></script>
<script>
window.onload = function () {
dp.SyntaxHighlighter.HighlightAll('code');
}
</script>
<!--<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-22034443-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>-->
</head>
<body>
<nav>
<a href="/">Home</a>
<a href="/contact">Contact</a>
</nav>
<article>
<header>
<h1>Hamcrest matchers</h1>
<p class="author">Author: Vidar Johansen></p>
<p class="published">Published: <time>2011-03-13</time></p>
</header>
<section>
<h2>What is this Hamcrest thing anyway?</h2>
<p>
<a href="http://code.google.com/p/hamcrest/" title="Hamcrest homepage">Hamcrest</a> is a library
of matcher objects. Those matchers are very useful when combined with a testing framework like
<a href="http://www.junit.org/" title="JUnit homepage">JUnit</a>. When used with JUnits
<code>Assert.assertThat</code> method, the language of your tests become more natural and
expresses what you mean in a better way then before. By using static imports in java, this becomes
even more expressive.
</p>
<h3>"Old-style" JUnit example</h3>
<pre name="code" class="java">
import static org.junit.Assert.assertNull;
@Test
public void shouldReturnNullWhenGivenNullValue() {
Translator translator = new EnglishToNorwegianTranslator();
String translatedMessage = translator.translate(null);
assertNull("Translator must handle null values", translatedMessage);
}
</pre>
<h3>Hamcrest-style JUnit example</h3>
<pre name="code" class="java">
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
@Test
public void shouldReturnNullWhenGivenNullValue() {
Translator translator = new EnglishToNorwegianTranslator();
String translatedMessage = translator.translate(null);
assertThat(translatedMessage, is(nullValue()));
}
</pre>
<h3>What's the fuss?</h3>
<p>
These examples are quite trivial, but show one of the strenght of using Hamcrest Matchers instead
of regular JUnit asserts. In the first example, I had to include a text describing what went wrong, or else
JUnit would just throw an AssertionError with no message, and you had to read and understand the code
to see what went wrong. In the Hamcrest example, I didn't include a description, but the output from JUnit
is more intuitive:
</p>
<pre>
<samp>
java.lang.AssertionError:
Expected: is null
got: "Some translated text";
</samp>
</pre>
</section>
<section>
<h2>Hamcrest Matchers</h2>
<p>
Hamcrest comes with a whole lot of Matchers bundled. <span class="note">Note: Hamcrest is also bundled with JUnit, so if you are using JUnit,
there's no need to download the separate Hamcrest jar.</span> The following matchers are included in <code>CoreMatchers</code>
(as listed in the <a href="http://code.google.com/p/hamcrest/wiki/Tutorial" title="Hamcrest tutorial">Hamcrest tutorial</a>):
</p>
<ul id="hamcrestCoreMatchers">
<li>Core
<dl>
<dt>anything</dt>
<dd>always matches, useful if you don't care what the object under test is</dd>
<dt>describedAs</dt>
<dd>decorator to adding custom failure description</dd>
<dt>is</dt>
<dd>decorator to improve readability</dd>
</dl>
</li>
<li>
Logical
<dl>
<dt>allOf</dt><dd>matches if all matchers match, short circuits (like Java &&)</dd>
<dt>anyOf</dt>
<dd>matches if any matchers match, short circuits (like Java ||)</dd>
<dt>not</dt>
<dd>matches if the wrapped matcher doesn't match and vice versa</dd>
</dl>
</li>
<li>
Object
<dl>
<dt>equalTo</dt>
<dd>test object equality using Object.equals</dd>
<dt>hasToString</dt>
<dd>test Object.toString</dd>
<dt>instanceOf</dt>
<dt>isCompatibleType</dt>
<dd>test type</dd>
<dt>notNullValue</dt>
<dt>nullValue</dt>
<dd>test for null</dd>
<dt>sameInstance</dt>
<dd>test object identity</dd>
</dl>
</li>
<li>
Beans
<dl>
<dt>hasProperty</dt>
<dd>test JavaBeans properties</dd>
</dl>
</li>
<li>Collections
<dl>
<dt>array</dt>
<dd>test an array's elements against an array of matchers</dd>
<dt>hasEntry</dt>
<dt>hasKey</dt>
<dt>hasValue</dt>
<dd>test a map contains an entry, key or value</dd>
<dt>hasItem</dt>
<dt>hasItems</dt>
<dd>test a collection contains elements</dd>
<dt>hasItemInArray</dt>
<dd>test an array contains an element</dd>
</dl>
</li>
<li>
Number
<dl>
<dt>closeTo</dt>
<dd>test floating point values are close to a given value</dd>
<dt>greaterThan</dt>
<dt>greaterThanOrEqualTo</dt>
<dt>lessThan</dt>
<dt>lessThanOrEqualTo</dt>
<dd>test ordering</dd>
</dl>
</li>
<li>
Text
<dl>
<dt>equalToIgnoringCase</dt>
<dd>test string equality ignoring case</dd>
<dt>equalToIgnoringWhiteSpace</dt>
<dd>test string equality ignoring differences in runs of whitespace</dd>
<dt>containsString</dt>
<dt>endsWith</dt>
<dt>endsWith</dt>
<dd>test string matching</dd>
</dl>
</li>
</ul>
</section>
<section>
<h2>Extending Hamcrest with custom matchers</h2>
<p>
The matchers included in Hamcrest <code>CoreMatchers</code> will take you a long way, and
will change the way you write your tests. But there will come a day when you might think
"this test could be written in a better way" or "this test just doesn't sound right". That
will be the day when you write your first custom matcher.
</p>
<h3>The <code>Matcher</code> interface</h3>
<p>
Buried in the javadoc, the <code>Matcher</code> interface reveals that you should not directly implement
<code>Matcher</code>, but rather use <code>BaseMatcher</code>. From the <a href="http://code.google.com/p/hamcrest/source/browse/trunk/hamcrest-java/hamcrest-core/src/main/java/org/hamcrest/Matcher.java">javadoc</a>:
</p>
<blockquote cite="http://code.google.com/p/hamcrest/source/browse/trunk/hamcrest-java/hamcrest-core/src/main/java/org/hamcrest/Matcher.java">
Matcher implementations should <em>NOT directly implement this interface</em>.
Instead, <em>extend</em> the <code>BaseMatcher</code> abstract class,
which will ensure that the Matcher API can grow to support
new features and remain compatible with all Matcher implementations.
</blockquote>
<p>
This leaves us with two options:
<ul>
<li>Derive from <code>BaseMatcher</code></li>
<li>Derive from <code>TypeSafeMatcher</code></li>
</ul>
</p>
<h3><code>BaseMatcher</code></h3>
<p>
<code>BaseMatcher</code> is the superclass of your choice when you don't really care about the
type of the value you are checking, or if you want the option of getting a null value.
You will need to implement the following methods:
<ul>
<li><code>public boolean matches(Object item);</code></li>
<li><code>public void describeTo(Description description);</code></li>
</ul>
</p>
<h3><code>TypeSafeMatcher</code></h3>
<p>
<code>TypeSafeMatcher</code> is the superclass of your choice when you care about the type of the
value you are checking, and you don't care about null values. <code>TypeSafeMatcher</code> checks
for null-values and cast the value into the correct type before invoking your methods.
You will nedd to implement the following methods:
<ul>
<li><code>public boolean matchesSafely(T item);</code></li>
<li><code>public void describeTo(Description description);</code></li>
</ul>
</p>
</section>
<article>
<!--<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'devilicious'; // required: replace example with your forum shortname
// The following are highly recommended additional parameters. Remove the slashes in front to use.
// var disqus_identifier = 'unique_dynamic_id_1234';
// var disqus_url = 'http://example.com/permalink-to-page.html';
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a>-->
</article>
</article>
<footer>
<p><a rel="license" href="http://creativecommons.org/licenses/by/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/Text" property="dct:title" rel="dct:type">Hamcrest Matchers</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://www.devilicious.org" property="cc:attributionName" rel="cc:attributionURL">Vidar Johansen</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>.</p>
</footer>
</body>
</html>