OLD | NEW |
1 library typed_mock; | 1 library typed_mock; |
2 | 2 |
3 | 3 |
4 _InvocationMatcher _lastMatcher; | 4 _InvocationMatcher _lastMatcher; |
5 | 5 |
6 | |
7 /// Enables stubbing methods. | 6 /// Enables stubbing methods. |
8 /// Use it when you want the mock to return particular value when particular | 7 /// |
9 /// method is called. | 8 /// Use it when you want the mock to return a particular value when a particular |
| 9 /// method, getter or setter is called. |
| 10 /// |
| 11 /// when(obj.testProperty).thenReturn(10); |
| 12 /// expect(obj.testProperty, 10); // pass |
| 13 /// |
| 14 /// You can specify multiple matchers, which are checked one after another. |
| 15 /// |
| 16 /// when(obj.testMethod(anyInt)).thenReturn('was int'); |
| 17 /// when(obj.testMethod(anyString)).thenReturn('was String'); |
| 18 /// expect(obj.testMethod(42), 'was int'); // pass |
| 19 /// expect(obj.testMethod('foo'), 'was String'); // pass |
| 20 /// |
| 21 /// You can even provide a function to calculate results. |
| 22 /// Function can be also used to capture invocation arguments (if you test some |
| 23 /// consumer). |
| 24 /// |
| 25 /// when(obj.testMethod(anyInt)).thenInvoke((int p) => 10 + p); |
| 26 /// expect(obj.testMethod(1), 11); // pass |
| 27 /// expect(obj.testMethod(5), 15); // pass |
10 Behavior when(_ignored) { | 28 Behavior when(_ignored) { |
11 try { | 29 try { |
12 var mock = _lastMatcher._mock; | 30 var mock = _lastMatcher._mock; |
13 mock._removeLastInvocation(); | 31 mock._removeLastInvocation(); |
14 // set behavior | 32 // set behavior |
15 var behavior = new Behavior._(_lastMatcher); | 33 var behavior = new Behavior._(_lastMatcher); |
16 _lastMatcher._behavior = behavior; | 34 _lastMatcher._behavior = behavior; |
17 return behavior; | 35 return behavior; |
18 } finally { | 36 } finally { |
19 // clear to prevent memory leak | 37 // clear to prevent memory leak |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 } | 122 } |
105 | 123 |
106 bool match(Invocation invocation) { | 124 bool match(Invocation invocation) { |
107 var arguments = invocation.positionalArguments; | 125 var arguments = invocation.positionalArguments; |
108 if (arguments.length != _matchers.length) { | 126 if (arguments.length != _matchers.length) { |
109 return false; | 127 return false; |
110 } | 128 } |
111 for (int i = 0; i < _matchers.length; i++) { | 129 for (int i = 0; i < _matchers.length; i++) { |
112 var matcher = _matchers[i]; | 130 var matcher = _matchers[i]; |
113 var argument = arguments[i]; | 131 var argument = arguments[i]; |
114 if (!matcher.match(argument)) { | 132 if (!matcher.matches(argument)) { |
115 return false; | 133 return false; |
116 } | 134 } |
117 } | 135 } |
118 return true; | 136 return true; |
119 } | 137 } |
120 } | 138 } |
121 | 139 |
122 | 140 |
123 class Behavior { | 141 class Behavior { |
124 final _InvocationMatcher _matcher; | 142 final _InvocationMatcher _matcher; |
125 | 143 |
126 Behavior._(this._matcher); | 144 Behavior._(this._matcher); |
127 | 145 |
128 bool _thenFunctionEnabled = false; | 146 bool _thenFunctionEnabled = false; |
129 Function _thenFunction; | 147 Function _thenFunction; |
130 | 148 |
131 bool _returnAlwaysEnabled = false; | 149 bool _returnAlwaysEnabled = false; |
132 var _returnAlways; | 150 var _returnAlways; |
133 | 151 |
134 bool _returnListEnabled = false; | 152 bool _returnListEnabled = false; |
135 List _returnList; | 153 List _returnList; |
136 int _returnListIndex; | 154 int _returnListIndex; |
137 | 155 |
138 bool _throwExceptionEnabled = false; | 156 bool _throwExceptionEnabled = false; |
139 var _throwException; | 157 var _throwException; |
140 | 158 |
| 159 /// Invokes the given [function] with actual arguments and returns its result. |
141 Behavior thenInvoke(Function function) { | 160 Behavior thenInvoke(Function function) { |
142 _reset(); | 161 _reset(); |
143 _thenFunctionEnabled = true; | 162 _thenFunctionEnabled = true; |
144 _thenFunction = function; | 163 _thenFunction = function; |
145 return this; | 164 return this; |
146 } | 165 } |
147 | 166 |
| 167 /// Returns the specific value. |
148 Behavior thenReturn(value) { | 168 Behavior thenReturn(value) { |
149 _reset(); | 169 _reset(); |
150 _returnAlwaysEnabled = true; | 170 _returnAlwaysEnabled = true; |
151 _returnAlways = value; | 171 _returnAlways = value; |
152 return this; | 172 return this; |
153 } | 173 } |
154 | 174 |
| 175 /// Returns values from the [list] starting from first to the last. |
| 176 /// If the end of list is reached a [StateError] is thrown. |
155 Behavior thenReturnList(List list) { | 177 Behavior thenReturnList(List list) { |
156 _reset(); | 178 _reset(); |
157 _returnListEnabled = true; | 179 _returnListEnabled = true; |
158 _returnList = list; | 180 _returnList = list; |
159 _returnListIndex = 0; | 181 _returnListIndex = 0; |
160 return this; | 182 return this; |
161 } | 183 } |
162 | 184 |
| 185 /// Throws the specified [exception] object. |
163 Behavior thenThrow(exception) { | 186 Behavior thenThrow(exception) { |
164 _reset(); | 187 _reset(); |
165 _throwExceptionEnabled = true; | 188 _throwExceptionEnabled = true; |
166 _throwException = exception; | 189 _throwException = exception; |
167 return this; | 190 return this; |
168 } | 191 } |
169 | 192 |
170 _reset() { | 193 _reset() { |
171 _thenFunctionEnabled = false; | 194 _thenFunctionEnabled = false; |
172 _returnAlwaysEnabled = false; | 195 _returnAlwaysEnabled = false; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 return; | 299 return; |
277 } | 300 } |
278 _mock._verifiedInvocations.add(invocation); | 301 _mock._verifiedInvocations.add(invocation); |
279 times++; | 302 times++; |
280 }); | 303 }); |
281 return times; | 304 return times; |
282 } | 305 } |
283 } | 306 } |
284 | 307 |
285 | 308 |
| 309 /// A class to extend mocks from. |
| 310 /// It supports specifying behavior using [when] and validation of interactions |
| 311 /// using [verify]. |
| 312 /// |
| 313 /// abstract class Name { |
| 314 /// String get firstName; |
| 315 /// String get lastName; |
| 316 /// } |
| 317 /// class NameMock extends TypedMock implements Name { |
| 318 /// noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| 319 /// } |
286 class TypedMock { | 320 class TypedMock { |
287 final Map<Symbol, List<_InvocationMatcher>> _matchersMap = {}; | 321 final Map<Symbol, List<_InvocationMatcher>> _matchersMap = {}; |
288 | 322 |
289 final List<Invocation> _invocations = []; | 323 final List<Invocation> _invocations = []; |
290 final Set<Invocation> _verifiedInvocations = new Set<Invocation>(); | 324 final Set<Invocation> _verifiedInvocations = new Set<Invocation>(); |
291 | 325 |
292 noSuchMethod(Invocation invocation) { | 326 noSuchMethod(Invocation invocation) { |
293 _invocations.add(invocation); | 327 _invocations.add(invocation); |
294 var member = invocation.memberName; | 328 var member = invocation.memberName; |
295 // prepare invocation matchers | 329 // prepare invocation matchers |
(...skipping 24 matching lines...) Expand all Loading... |
320 notVerified(e) => !_verifiedInvocations.contains(e); | 354 notVerified(e) => !_verifiedInvocations.contains(e); |
321 return _invocations.where(notVerified); | 355 return _invocations.where(notVerified); |
322 } | 356 } |
323 | 357 |
324 void _removeLastInvocation() { | 358 void _removeLastInvocation() { |
325 _invocations.removeLast(); | 359 _invocations.removeLast(); |
326 } | 360 } |
327 } | 361 } |
328 | 362 |
329 | 363 |
| 364 /// [ArgumentMatcher] checks whether the given argument satisfies some |
| 365 /// condition. |
330 abstract class ArgumentMatcher { | 366 abstract class ArgumentMatcher { |
331 bool match(val); | 367 /// Checks whether this matcher accepts the given argument. |
| 368 bool matches(val); |
332 } | 369 } |
333 | 370 |
334 | 371 |
335 class _ArgumentMatcher_equals extends ArgumentMatcher { | 372 class _ArgumentMatcher_equals extends ArgumentMatcher { |
336 final expected; | 373 final expected; |
337 | 374 |
338 _ArgumentMatcher_equals(this.expected); | 375 _ArgumentMatcher_equals(this.expected); |
339 | 376 |
340 @override | 377 @override |
341 bool match(val) { | 378 bool matches(val) { |
342 return val == expected; | 379 return val == expected; |
343 } | 380 } |
344 } | 381 } |
345 | 382 |
| 383 /// Matches an argument that is equal to the given [expected] value. |
346 equals(expected) { | 384 equals(expected) { |
347 return new _ArgumentMatcher_equals(expected); | 385 return new _ArgumentMatcher_equals(expected); |
348 } | 386 } |
349 | 387 |
350 | 388 |
351 class _ArgumentMatcher_anyBool extends ArgumentMatcher { | 389 class _ArgumentMatcher_anyBool extends ArgumentMatcher { |
352 @override | 390 @override |
353 bool match(val) { | 391 bool matches(val) { |
354 return val is bool; | 392 return val is bool; |
355 } | 393 } |
356 } | 394 } |
357 | 395 |
| 396 /// Matches any [bool] value. |
358 final anyBool = new _ArgumentMatcher_anyBool(); | 397 final anyBool = new _ArgumentMatcher_anyBool(); |
359 | 398 |
360 | 399 |
361 class _ArgumentMatcher_anyInt extends ArgumentMatcher { | 400 class _ArgumentMatcher_anyInt extends ArgumentMatcher { |
362 @override | 401 @override |
363 bool match(val) { | 402 bool matches(val) { |
364 return val is int; | 403 return val is int; |
365 } | 404 } |
366 } | 405 } |
367 | 406 |
| 407 /// Matches any [int] value. |
368 final anyInt = new _ArgumentMatcher_anyInt(); | 408 final anyInt = new _ArgumentMatcher_anyInt(); |
369 | 409 |
370 | 410 |
371 class _ArgumentMatcher_anyObject extends ArgumentMatcher { | 411 class _ArgumentMatcher_anyObject extends ArgumentMatcher { |
372 @override | 412 @override |
373 bool match(val) { | 413 bool matches(val) { |
374 return true; | 414 return true; |
375 } | 415 } |
376 } | 416 } |
377 | 417 |
| 418 /// Matches any [Object] (or subclass) value. |
378 final anyObject = new _ArgumentMatcher_anyObject(); | 419 final anyObject = new _ArgumentMatcher_anyObject(); |
379 | 420 |
380 | 421 |
381 class _ArgumentMatcher_anyString extends ArgumentMatcher { | 422 class _ArgumentMatcher_anyString extends ArgumentMatcher { |
382 @override | 423 @override |
383 bool match(val) { | 424 bool matches(val) { |
384 return val is String; | 425 return val is String; |
385 } | 426 } |
386 } | 427 } |
387 | 428 |
| 429 /// Matches any [String] value. |
388 final anyString = new _ArgumentMatcher_anyString(); | 430 final anyString = new _ArgumentMatcher_anyString(); |
OLD | NEW |