Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(745)

Side by Side Diff: lib/unittest/mock.dart

Issue 10827201: Added the ability to tun off logging for individual behaviors. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * The error formatter for mocking is a bit different from the default one 6 * The error formatter for mocking is a bit different from the default one
7 * for unit testing; instead of the third argument being a 'reason' 7 * for unit testing; instead of the third argument being a 'reason'
8 * it is instead a [signature] describing the method signature filter 8 * it is instead a [signature] describing the method signature filter
9 * that was used to select the logs that were verified. 9 * that was used to select the logs that were verified.
10 */ 10 */
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 arg5, arg6, arg7, arg8, arg9); 197 arg5, arg6, arg7, arg8, arg9);
198 } 198 }
199 199
200 /** 200 /**
201 * A [Behavior] represents how a [Mock] will respond to one particular 201 * A [Behavior] represents how a [Mock] will respond to one particular
202 * type of method call. 202 * type of method call.
203 */ 203 */
204 class Behavior { 204 class Behavior {
205 CallMatcher matcher; // The method call matcher. 205 CallMatcher matcher; // The method call matcher.
206 List<Responder> actions; // The values to return/throw or proxies to call. 206 List<Responder> actions; // The values to return/throw or proxies to call.
207 bool logging = true;
207 208
208 Behavior (this.matcher) { 209 Behavior (this.matcher) {
209 actions = new List<Responder>(); 210 actions = new List<Responder>();
210 } 211 }
211 212
212 /** 213 /**
213 * Adds a [Responder] that returns a [value] for [count] calls 214 * Adds a [Responder] that returns a [value] for [count] calls
214 * (1 by default). 215 * (1 by default).
215 */ 216 */
216 Behavior thenReturn(value, [count = 1]) { 217 Behavior thenReturn(value, [count = 1]) {
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 LogEntryList verify(Matcher matcher) { 421 LogEntryList verify(Matcher matcher) {
421 if (_mockFailureHandler == null) { 422 if (_mockFailureHandler == null) {
422 _mockFailureHandler = 423 _mockFailureHandler =
423 new _MockFailureHandler(getOrCreateExpectFailureHandler()); 424 new _MockFailureHandler(getOrCreateExpectFailureHandler());
424 } 425 }
425 expect(logs, matcher, filter, _mockFailureHandler); 426 expect(logs, matcher, filter, _mockFailureHandler);
426 return this; 427 return this;
427 } 428 }
428 429
429 /** 430 /**
431 * Iterate through the list and call the [validator] function with the
432 * log [List] and position. The [validator] should return the number of
433 * positions to advance upon success, or zero upon failure. When zero is
434 * returned an error is reported. [reason] can be used to provide a
435 * more descriptive failure message. If a failure occurred false will be
436 * returned (unless the failure handler itself threw an exception);
437 * otherwise true is returned.
438 * The use case here is to perform more complex validations; for example
439 * we may want to assert that the return value from some function is
440 * later used as a parameter to a following function. If we filter the logs
441 * to include just these two functions we can write a simple validator to
442 * do this check.
443 */
444 bool stepwiseValidate(Function validator, [String reason = '']) {
Siggi Cherem (dart-lang) 2012/08/07 23:58:47 looking at the test, I think it is worth defining
445 if (_mockFailureHandler == null) {
446 _mockFailureHandler =
447 new _MockFailureHandler(getOrCreateExpectFailureHandler());
448 }
449 var i = 0;
450 while (i < logs.length) {
451 var n = validator(logs, i);
452 if (n == 0) {
453 if (reason.length > 0) {
454 reason = ': $reason';
455 }
456 _mockFailureHandler.fail("Stepwise validation failed at $filter "
457 "position $i$reason");
458 return false;
459 } else {
460 i += n;
461 }
462 }
463 return true;
464 }
465
466 /**
430 * Turn the logs into human-readable text. If [baseTime] is specified 467 * Turn the logs into human-readable text. If [baseTime] is specified
431 * then each entry is prefixed with the offset from that time in 468 * then each entry is prefixed with the offset from that time in
432 * milliseconds; otherwise the time of day is used. 469 * milliseconds; otherwise the time of day is used.
433 */ 470 */
434 String toString([Date baseTime]) { 471 String toString([Date baseTime]) {
435 String s = ''; 472 String s = '';
436 for (var e in logs) { 473 for (var e in logs) {
437 s = '$s${e.toString(baseTime)}\n'; 474 s = '$s${e.toString(baseTime)}\n';
438 } 475 }
439 return s; 476 return s;
440 } 477 }
441 478
442 /** 479 /**
443 * Find the first log entry that satisfies [logFilter] and 480 * Find the first log entry that satisfies [logFilter] and
444 * return its position. A search [start] position can be provided 481 * return its position. A search [start] position can be provided
445 * to allow for repeated searches. [logFilter] can be a [CallMatcher], 482 * to allow for repeated searches. [logFilter] can be a [CallMatcher],
446 * or a predicate function that takes a [LogEntry] argument and returns 483 * or a predicate function that takes a [LogEntry] argument and returns
447 * a bool. If [logFilter] is null, it will match any [LogEntry]. 484 * a bool. If [logFilter] is null, it will match any [LogEntry].
448 * If no entry is found, then [failureReturnValue] is returned. 485 * If no entry is found, then [failureReturnValue] is returned.
486 * After each check the position is updated by [skip], so using
487 * [skip] of -1 allows backward searches.
449 */ 488 */
450 int findLogEntry(logFilter, [int start = 0, int failureReturnValue = -1]) { 489 int findLogEntry(logFilter, [int start = 0, int failureReturnValue = -1,
490 skip = 1]) {
451 logFilter = _makePredicate(logFilter); 491 logFilter = _makePredicate(logFilter);
452 int pos = start; 492 int pos = start;
453 while (pos < logs.length) { 493 while (pos >= 0 && pos < logs.length) {
454 if (logFilter(logs[pos])) { 494 if (logFilter(logs[pos])) {
455 return pos; 495 return pos;
456 } 496 }
457 ++pos; 497 pos += skip;
458 } 498 }
459 return failureReturnValue; 499 return failureReturnValue;
460 } 500 }
461 501
462 /** 502 /**
463 * Returns log events that happened up to the first one that 503 * Returns log events that happened up to the first one that
464 * satisfies [logFilter]. If [inPlace] is true, then returns 504 * satisfies [logFilter]. If [inPlace] is true, then returns
465 * this LogEntryList after removing the from the first satisfier; 505 * this LogEntryList after removing the from the first satisfier;
466 * onwards otherwise a new list is created. [description] 506 * onwards otherwise a new list is created. [description]
467 * is used to create a new name for the resulting list. 507 * is used to create a new name for the resulting list.
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after
1063 LogEntryList sharedLog = null; 1103 LogEntryList sharedLog = null;
1064 1104
1065 /** 1105 /**
1066 * [Mock] is the base class for all mocked objects, with 1106 * [Mock] is the base class for all mocked objects, with
1067 * support for basic mocking. 1107 * support for basic mocking.
1068 * 1108 *
1069 * To create a mock objects for some class T, create a new class using: 1109 * To create a mock objects for some class T, create a new class using:
1070 * 1110 *
1071 * class MockT extends Mock implements T {}; 1111 * class MockT extends Mock implements T {};
1072 * 1112 *
1073 * Then specify the behavior of the Mock for different methods using 1113 * Then specify the [Behavior] of the Mock for different methods using
1074 * [when] (to select the method and parameters) and [thenReturn], 1114 * [when] (to select the method and parameters) and then the [Action]s
1075 * [alwaysReturn], [thenThrow], [alwaysThrow], [thenCall] or [alwaysCall]. 1115 * for the [Behavior] by calling [thenReturn], [alwaysReturn], [thenThrow],
1116 * [alwaysThrow], [thenCall] or [alwaysCall].
1117 *
1076 * [thenReturn], [thenThrow] and [thenCall] are one-shot so you would 1118 * [thenReturn], [thenThrow] and [thenCall] are one-shot so you would
1077 * typically call these more than once to specify a sequence of actions; 1119 * typically call these more than once to specify a sequence of actions;
1078 * this can be done with chained calls, e.g.: 1120 * this can be done with chained calls, e.g.:
1079 * 1121 *
1080 * m.when(callsTo('foo')). 1122 * m.when(callsTo('foo')).
1081 * thenReturn(0).thenReturn(1).thenReturn(2); 1123 * thenReturn(0).thenReturn(1).thenReturn(2);
1082 * 1124 *
1083 * [thenCall] and [alwaysCall] allow you to proxy mocked methods, chaining 1125 * [thenCall] and [alwaysCall] allow you to proxy mocked methods, chaining
1084 * to some other implementation. This provides a way to implement 'spies'. 1126 * to some other implementation. This provides a way to implement 'spies'.
1085 * 1127 *
1128 * You can disable logging for a particular [Behavior] easily:
1129 *
1130 * m.when(callsTo('bar')).logging = false;
1131 *
1086 * You can then use the mock object. Once you are done, to verify the 1132 * You can then use the mock object. Once you are done, to verify the
1087 * behavior, use [getLogs] to extract a relevant subset of method call 1133 * behavior, use [getLogs] to extract a relevant subset of method call
1088 * logs and apply [Matchers] to these through calling [verify]. 1134 * logs and apply [Matchers] to these through calling [verify].
1089 * 1135 *
1090 * A Mock can be given a name when constructed. In this case instead of 1136 * A Mock can be given a name when constructed. In this case instead of
1091 * keeping its own log, it uses a shared log. This can be useful to get an 1137 * keeping its own log, it uses a shared log. This can be useful to get an
1092 * audit trail of interleaved behavior. It is the responsibility of the user 1138 * audit trail of interleaved behavior. It is the responsibility of the user
1093 * to ensure that mock names, if used, are unique. 1139 * to ensure that mock names, if used, are unique.
1094 * 1140 *
1095 * Limitations: 1141 * Limitations:
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1240 // Note that for endlessly repeating values, we started the count at 1286 // Note that for endlessly repeating values, we started the count at
1241 // 0, so we get a potentially useful value here, which is the 1287 // 0, so we get a potentially useful value here, which is the
1242 // (negation of) the number of times we returned the value. 1288 // (negation of) the number of times we returned the value.
1243 if (--response.count == 0) { 1289 if (--response.count == 0) {
1244 actions.removeRange(0, 1); 1290 actions.removeRange(0, 1);
1245 } 1291 }
1246 // Do the response. 1292 // Do the response.
1247 Action action = response.action; 1293 Action action = response.action;
1248 var value = response.value; 1294 var value = response.value;
1249 if (action == Action.RETURN) { 1295 if (action == Action.RETURN) {
1250 if (_logging) { 1296 if (_logging && b.logging) {
1251 log.add(new LogEntry(name, method, args, action, value)); 1297 log.add(new LogEntry(name, method, args, action, value));
1252 } 1298 }
1253 return value; 1299 return value;
1254 } else if (action == Action.THROW) { 1300 } else if (action == Action.THROW) {
1255 if (_logging) { 1301 if (_logging && b.logging) {
1256 log.add(new LogEntry(name, method, args, action, value)); 1302 log.add(new LogEntry(name, method, args, action, value));
1257 } 1303 }
1258 throw value; 1304 throw value;
1259 } else if (action == Action.PROXY) { 1305 } else if (action == Action.PROXY) {
1260 var rtn; 1306 var rtn;
1261 switch (args.length) { 1307 switch (args.length) {
1262 case 0: 1308 case 0:
1263 rtn = value(); 1309 rtn = value();
1264 break; 1310 break;
1265 case 1: 1311 case 1:
(...skipping 28 matching lines...) Expand all
1294 args[4], args[5], args[6], args[7], args[8]); 1340 args[4], args[5], args[6], args[7], args[8]);
1295 break; 1341 break;
1296 case 9: 1342 case 9:
1297 rtn = value(args[0], args[1], args[2], args[3], 1343 rtn = value(args[0], args[1], args[2], args[3],
1298 args[4], args[5], args[6], args[7], args[8], args[9]); 1344 args[4], args[5], args[6], args[7], args[8], args[9]);
1299 break; 1345 break;
1300 default: 1346 default:
1301 throw new Exception( 1347 throw new Exception(
1302 "Cannot proxy calls with more than 10 parameters."); 1348 "Cannot proxy calls with more than 10 parameters.");
1303 } 1349 }
1304 if (_logging) { 1350 if (_logging && b.logging) {
1305 log.add(new LogEntry(name, method, args, action, rtn)); 1351 log.add(new LogEntry(name, method, args, action, rtn));
1306 } 1352 }
1307 return rtn; 1353 return rtn;
1308 } 1354 }
1309 } 1355 }
1310 } 1356 }
1311 if (matchedMethodName) { 1357 if (matchedMethodName) {
1312 // User did specify behavior for this method, but all the 1358 // User did specify behavior for this method, but all the
1313 // actions are exhausted. This is considered an error. 1359 // actions are exhausted. This is considered an error.
1314 throw new Exception('No more actions for method ' 1360 throw new Exception('No more actions for method '
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1374 arg3 = _noArg, 1420 arg3 = _noArg,
1375 arg4 = _noArg, 1421 arg4 = _noArg,
1376 arg5 = _noArg, 1422 arg5 = _noArg,
1377 arg6 = _noArg, 1423 arg6 = _noArg,
1378 arg7 = _noArg, 1424 arg7 = _noArg,
1379 arg8 = _noArg, 1425 arg8 = _noArg,
1380 arg9 = _noArg]) => 1426 arg9 = _noArg]) =>
1381 getLogs(callsTo(method, arg0, arg1, arg2, arg3, arg4, 1427 getLogs(callsTo(method, arg0, arg1, arg2, arg3, arg4,
1382 arg5, arg6, arg7, arg8, arg9)); 1428 arg5, arg6, arg7, arg8, arg9));
1383 } 1429 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698