1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """
22 Achoo is a fluent interface for testing Python objects.
23
24 It is designed to be used in conjunction with a unit testing
25 framework like PyUnit's C{unittest} module, shipped with all modern
26 Python distributions.
27
28 To use Achoo, import the assertion builder functions then use them
29 to wire up assertions about objects and callables.
30
31 The two assertion builder functions are C{requiring} - used to test
32 properties of objects and C{calling}, used to test properties of a
33 calling a callable object (that is, a function, method or similar).
34 These functions returns assertion builders that can be used to chain
35 assertions calls together. See the documentation for the functions
36 for more information.
37
38 If any of the assertions are not met, an C{AssertionError} is raised.
39
40 For example::
41
42 import unittest
43 from achoo import requiring
44 from achoo import calling
45
46 class StringTest(unittest.TestCase):
47
48 def testLength(self):
49 s = 'foo'
50 requiring(s.length).equal_to(3)
51
52 def testStrip(self):
53 s = ' foo '
54 calling(s.strip).returns('foo')
55
56 def testSplit(self):
57 s = 'foo,bar'
58 calling(s.split).passing(',').returns()\
59 .length(2)\
60 .index(0).equal_to('foo')\
61 .index(1).equal_to('bar')
62
63 def testBadIndex(self):
64 s = 'foo'
65 calling(s.index).passing('quux').raises(ValueError)
66
67 """
68
69 import sys
70
71 import gettext
72 _ = gettext.translation('achoo', fallback=True).ugettext
73
74
76 """
77 Assertion builder factory for object properties.
78
79 To test an object, call C{requiring} and pass the object as the
80 sole argument. A C{ValueAssertionBuilder} is returned and can be used
81 to chain together assertions about it.
82
83 For example::
84
85 test_map = {'foo': 'bar'}
86 requiring(test_map)\
87 .length(1)\
88 .contains('foo')\
89 .index('foo').equal_to('bar')
90
91 @return: an instance of C{ValueAssertionBuilder} wrapping the value
92 passed in
93 @param value: an object to be tested
94 """
95
96
97
98
99 return ValueAssertionBuilder(value)
100
101
103 """
104 An assertion builder for testing properties of objects.
105
106 This object can be used to create a set of assertions about various
107 properties of an object. Most methods return a builder with the
108 same object so that more than one assertion to be made about it.
109
110 If any of the assertions fail, an C{AssertionError} is raised.
111 """
112
113 - def __init__(self, value, invert=False):
114 """
115 Constructs a new builder.
116
117 In general, you want to use the C{requiring} function instead
118 of this directly.
119
120 @param value: an object to be tested
121 @param invert: optionally inverts the sense of the next assertion
122 if C{True}
123 """
124 self.value = value
125 self.invert_sense = invert
126
127
128 @property
130 """
131 Inverts the sense of the next assertion.
132
133 This property causes the boolean sense of the next assertion
134 to be inverted. That is, if a call to C{equal_to} is prefixed
135 with C{is_not}, it will raise an error if the value object is
136 not equal to the given value. All other subsequent assertions
137 retain the specified sense unless also prefixed with C{is_not}.
138
139 For example::
140
141 s = 'foo'
142 requiring(s.length).is_not.equal_to(0)
143
144 """
145 return ValueAssertionBuilder(self.value, True)
146
147
149 """
150 Asserts the value object is equal to some other object.
151
152 @return: this assertion builder
153 @param other: another object to test against the builder's
154 value object
155 @raise AssertionError: if the builder's value is not equal to
156 C{other}
157 """
158 if self.value != other and not self.invert_sense:
159 raise self._error(_('Value `%s\' expected to equal `%s\''),
160 _('Value `%s\' not expected to equal `%s\''),
161 other)
162 self.invert_sense = False
163 return self
164
165
167 """
168 Asserts the value object is the same as another object.
169
170 @return: this assertion builder
171 @param other: another object to test for same identity
172 @raise AssertionError: if the builder's value is not the same
173 object as C{other}
174 """
175 if self.value is not other and not self.invert_sense:
176 raise self._error(_('Value `%s\' expected to be `%s\''),
177 _('Value `%s\' not expected to be `%s\''),
178 other)
179 self.invert_sense = False
180 return self
181
182
184 """
185 Asserts the value object is C{None}.
186
187 @return: this assertion builder
188 @raise AssertionError: if the builder's value is not C{None}
189 """
190 return self.same_as(None)
191
192
194 """
195 Asserts the value object is not C{None}.
196
197 @return: this assertion builder
198 @raise AssertionError: if the builder's value is C{None}
199 """
200 if self.value is None and not self.invert_sense:
201 raise self._error(_('Value `%s\' expected to be `%s\''),
202 _('Value `%s\' not expected to be `%s\''),
203 None)
204 self.invert_sense = False
205 return self
206
207
208 - def is_a(self, clazz):
209 """
210 Asserts the value object is an instance of a particular type.
211
212 @return: this assertion builder
213 @param clazz: type the value must be an instance of
214 @raise AssertionError: if the builder's value is not an instance
215 of C{clazz}
216 """
217 if not isinstance(self.value, clazz) and not self.invert_sense:
218 raise self._error(_('Value `%s\' expected to be a `%s\''),
219 _('Value `%s\' not expected to be a `%s\''),
220 clazz)
221 self.invert_sense = False
222 return self
223
224
226 """
227 Asserts the value object has a specific length.
228
229 @return: this assertion builder
230 @param length: the value that must be returned by passing
231 the builder value to the C{len} built-in
232 @raise AssertionError: if the length of the builder's value is
233 not equal to C{length}
234 """
235 if len(self.value) != length and not self.invert_sense:
236 raise self._error(_('Length of `%s\' expected to equal `%s\''),
237 _('Length of `%s\' not expected to equal `%s\''),
238 length)
239 self.invert_sense = False
240 return self
241
242
244 """
245 Asserts the value object contains a specific element.
246
247 @return: this assertion builder
248 @param element: the element that must be contained by the
249 value object, as tested using the keyword C{in}
250 @raise AssertionError: if the builder's value does not contain
251 C{element}
252 """
253 if element not in self.value and not self.invert_sense:
254 raise self._error(_('Value `%s\' expected to contain `%s\''),
255 _('Value of `%s\' not expected to contain `%s\''),
256 element)
257 self.invert_sense = False
258 return self
259
260
262 """
263 Asserts the value object has a specific index.
264
265 B{Note:} this method returns a builder for the object at the
266 given index, allowing assertions to be made about that object
267 but not allowing any additional assertions to be made about
268 the original object.
269
270 The C{is_not} modifier has no effect on this method.
271
272 For example::
273
274 test_map = {'foo': 'bar'}
275 requiring(test_map).index('foo').equal_to('bar')
276
277 @return: an assertion builder for the object at the given
278 index
279 @param index: the index that must be contained by the
280 value object, as tested using the keyword C{in}
281 @raise AssertionError: if the builder's value does not contain
282 an element at C{index}
283 """
284 if self.invert_sense:
285 raise AssertionError\
286 (_('A call to `index\' cannot be preceded by `is_not\''))
287
288 try:
289 return ValueAssertionBuilder(self.value[index])
290 except KeyError:
291 raise self._error(_('Value `%s\' expected to contain key `%s\''),
292 None, index)
293 except IndexError:
294 raise self._error(_('Value `%s\' expected to contain index `%s\''),
295 None, index)
296
297 - def _error(self, message, inverse_message, other):
298 """
299 Returns a new C{AssertionError} with an appropriate message.
300 """
301 return AssertionError((message
302 if not self.invert_sense
303 else inverse_message) % (self.value, other))
304
305
307 """
308 Assertion builder factory for callable objects.
309
310 To test a callable, call C{requiring} and pass the object as the
311 sole argument. A C{ValueAssertionBuilder} is returned and can be used
312 to chain together assertions about it.
313
314 For example::
315
316 incr = lambda x: x + 1
317 calling(incr).passing(1).returns(2)
318 calling(incr).raises(TypeError)
319
320 @return: an instance of C{CallableAssertionBuilder} wrapping the
321 callable passed in
322 @param callabl: a callable object (function, method or similar) to
323 be tested
324 """
325
326
327
328
329 return CallableAssertionBuilder(callabl)
330
331
333 """
334 An assertion builder for testing callable objects.
335
336 This object can be used to create a set of assertions about
337 conditions when calling a callable object, such as a function
338 or method.
339
340 To provide parameters to the callable, use the C{passing} method.
341 The callable is not actually executed until one of the return
342 or raises methods is called.
343 """
344
346 """
347 Constructs a new builder.
348
349 In general, you want to use the C{calling} function instead
350 of this directly.
351
352 @param callabl: an object to be tested
353 """
354 self.callable = callabl
355 self.args = None
356 self.kwargs = None
357
358 - def passing(self, *args, **kwargs):
359 """
360 Applies a set of arguments to be passed to the callable.
361
362 Use this method to specify what positional and keyword arguments
363 should be passed to the callable.
364
365 @return: this assertion builder
366 @param args: positional arguments to be passed to the callable
367 @param kwargs: keyword arguments to be passed to the callable
368 """
369 self.args = args
370 self.kwargs = kwargs
371 return self
372
374 """
375 Invokes the callable, optionally checking the returned value.
376
377 Calling this method will cause the callable to be invoked,
378 with any arguments specified using C{passing} and returning
379 a C{ValueAssertionBuilder} for the object returned by the
380 callable.
381
382 An object can be optionally passed to this method for
383 conveniently checking the value of the object returned
384 by the callable.
385
386 @return: a C{ValueAssertionBuilder} for the object returned
387 by the invocation of the callable
388 @param value: optional value that must be equal to the
389 object returned by invoking the callable
390 @raise AssertionError: if the returned value is not equal to
391 C{value}
392 """
393 ret = self._invoke()
394 builder = requiring(ret)
395 if value is not None:
396 builder.equal_to(value)
397 return builder
398
400 """
401 Invokes the callable and ensures the return value is C{None}.
402
403 Calling this method will cause the callable to be invoked,
404 with any arguments specified using C{passing}.
405
406 @raise AssertionError: if the value returned by invoking
407 the callable is not equal to C{None}
408 """
409 self.returns().is_none()
410
412 """
413 Invokes the callable, ensuring it raises an exception.
414
415 Calling this method will cause the callable to be invoked,
416 with any arguments specified using C{passing}.
417
418 A C{ValueAssertionBuilder} for the exception is returned,
419 allowing its properties to be examined.
420
421 @return: a C{ValueAssertionBuilder} for the exception raised
422 by the invocation of the callable
423 @param error: type of the exception to be raised
424 @raise AssertionError: if the callable invocation did not
425 raise an exception or if it raised an exception that was
426 not of type C{BaseException}
427 """
428 try:
429 self._invoke()
430 except:
431 e_type, e_value, tb = sys.exc_info()
432 if e_type == error:
433 return requiring(e_value)
434
435 raise AssertionError(_('Calling `%s\' raised a `%s\' error')
436 % (self.callable, e_type))
437 else:
438 raise AssertionError(_('Calling `%s\' did not raise any error')
439 % self.callable)
440
442 """
443 Invokes the callable with any parameters that have been specified.
444
445 @return: the return value from the callable invocation
446 """
447 if self.args and self.kwargs:
448 return self.callable(*self.args, **self.kwargs)
449 if self.args:
450 return self.callable(*self.args)
451 if self.kwargs:
452 return self.callable(**self.kwargs)
453 return self.callable()
454