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

Side by Side Diff: test/invoker_test.dart

Issue 916533003: Add an Invoker class that manages a running test. (Closed) Base URL: git@github.com:dart-lang/unittest@master
Patch Set: Created 5 years, 10 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
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
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.
4
5 import 'dart:async';
6 import 'dart:collection';
7
8 import 'package:fake_async/fake_async.dart';
9 import 'package:unittest/src/invoker.dart';
10 import 'package:unittest/src/live_test.dart';
11 import 'package:unittest/src/state.dart';
12 import 'package:unittest/src/suite.dart';
13 import 'package:unittest/unittest.dart';
14
15 import 'utils.dart';
16
17 // The last state change detected via [expectStates].
18 State lastState;
kevmoo 2015/02/11 00:35:09 If things are not used by another lib, make them p
nweiz 2015/02/11 02:07:06 Done.
19
20 void main() {
21 var suite;
22 setUp(() {
23 lastState = null;
24 suite = new Suite("suite", []);
25 });
26
27 group("Invoker.current", () {
28 test("returns null outside of a test body", () {
29 expect(Invoker.current, isNull);
30 });
31
32 test("returns the current invoker in a test body", () {
33 var invoker;
34 var liveTest = new LocalTest("test", () {
35 invoker = Invoker.current;
36 }).load(suite);
37 liveTest.onError.listen(expectAsync((_) {}, count: 0));
38
39 return liveTest.run().then((_) {
40 expect(invoker.liveTest, equals(liveTest));
41 });
42 });
43
44 test("returns the current invoker in a test body after the test completes",
45 () {
46 var status;
47 var completer = new Completer();
48 var liveTest = new LocalTest("test", () {
49 // Use [new Future] in particular to wait longer than a microtask for
50 // the test to complete.
51 new Future(() {
52 status = Invoker.current.liveTest.state.status;
53 completer.complete(Invoker.current);
54 });
55 }).load(suite);
56 liveTest.onError.listen(expectAsync((_) {}, count: 0));
57
58 expect(liveTest.run(), completes);
59 return completer.future.then((invoker) {
60 expect(invoker.liveTest, equals(liveTest));
61 expect(status, equals(Status.complete));
62 });
63 });
64
65 test("returns the current invoker in a tearDown body", () {
66 var invoker;
67 var liveTest = new LocalTest("test", () {}, tearDown: () {
68 invoker = Invoker.current;
69 }).load(suite);
70 liveTest.onError.listen(expectAsync((_) {}, count: 0));
71
72 return liveTest.run().then((_) {
73 expect(invoker.liveTest, equals(liveTest));
74 });
75 });
76
77 test("returns the current invoker in a tearDown body after the test "
78 "completes", () {
79 var status;
80 var completer = new Completer();
81 var liveTest = new LocalTest("test", () {}, tearDown: () {
82 // Use [new Future] in particular to wait longer than a microtask for
83 // the test to complete.
84 new Future(() {
85 status = Invoker.current.liveTest.state.status;
86 completer.complete(Invoker.current);
87 });
88 }).load(suite);
89 liveTest.onError.listen(expectAsync((_) {}, count: 0));
90
91 expect(liveTest.run(), completes);
92 return completer.future.then((invoker) {
93 expect(invoker.liveTest, equals(liveTest));
94 expect(status, equals(Status.complete));
95 });
96 });
97 });
98
99 group("in a successful test,", () {
100 test("the state changes from pending to running to complete", () {
101 var stateInTest;
102 var stateInTearDown;
103 var liveTest;
104 liveTest = new LocalTest("test", () {
105 stateInTest = liveTest.state;
106 }, tearDown: () {
107 stateInTearDown = liveTest.state;
108 }).load(suite);
109 liveTest.onError.listen(expectAsync((_) {}, count: 0));
110
111 expect(liveTest.state.status, equals(Status.pending));
112 expect(liveTest.state.result, equals(Result.success));
113
114 var future = liveTest.run();
115
116 expect(liveTest.state.status, equals(Status.running));
117 expect(liveTest.state.result, equals(Result.success));
118
119 return future.then((_) {
120 expect(stateInTest.status, equals(Status.running));
121 expect(stateInTest.result, equals(Result.success));
122
123 expect(stateInTearDown.status, equals(Status.running));
124 expect(stateInTearDown.result, equals(Result.success));
125
126 expect(liveTest.state.status, equals(Status.complete));
127 expect(liveTest.state.result, equals(Result.success));
128 });
129 });
130
131 test("onStateChange fires for each state change", () {
132 var liveTest = new LocalTest("test", () {}).load(suite);
133 liveTest.onError.listen(expectAsync((_) {}, count: 0));
134
135 var first = true;
136 liveTest.onStateChange.listen(expectAsync((state) {
137 if (first) {
138 expect(state.status, equals(Status.running));
139 first = false;
140 } else {
141 expect(state.status, equals(Status.complete));
142 }
143 expect(state.result, equals(Result.success));
144 }, count: 2, max: 2));
145
146 return liveTest.run();
147 });
148
149 test("onComplete completes once the test body and tearDown are done", () {
150 var testRun = false;
151 var tearDownRun = false;
152 var liveTest = new LocalTest("test", () {
153 testRun = true;
154 }, tearDown: () {
155 tearDownRun = true;
156 }).load(suite);
157
158 expect(liveTest.onComplete.then((_) {
159 expect(testRun, isTrue);
160 expect(tearDownRun, isTrue);
161 }), completes);
162
163 return liveTest.run();
164 });
165 });
166
167 group("in a test with failures,", () {
168 test("a synchronous throw is reported and causes the test to fail", () {
169 var liveTest = new LocalTest("test", () {
170 throw new TestFailure('oh no');
171 }).load(suite);
172
173 expectSingleFailure(liveTest);
174 return liveTest.run();
175 });
176
177 test("a synchronous reported failure causes the test to fail", () {
178 var liveTest = new LocalTest("test", () {
179 Invoker.current.handleError(new TestFailure("oh no"));
180 }).load(suite);
181
182 expectSingleFailure(liveTest);
183 return liveTest.run();
184 });
185
186 test("a failure reported asynchronously during the test causes it to fail",
187 () {
188 var liveTest = new LocalTest("test", () {
189 Invoker.current.addOutstandingCallback();
190 new Future(() => Invoker.current.handleError(new TestFailure("oh no")));
191 }).load(suite);
192
193 expectSingleFailure(liveTest);
194 return liveTest.run();
195 });
196
197 test("a failure thrown asynchronously during the test causes it to fail",
198 () {
199 var liveTest = new LocalTest("test", () {
200 Invoker.current.addOutstandingCallback();
201 new Future(() => throw new TestFailure("oh no"));
202 }).load(suite);
203
204 expectSingleFailure(liveTest);
205 return liveTest.run();
206 });
207
208 test("a failure reported asynchronously after the test causes it to error",
209 () {
210 var liveTest = new LocalTest("test", () {
211 new Future(() => Invoker.current.handleError(new TestFailure("oh no")));
212 }).load(suite);
213
214 expectStates(liveTest, [
215 const State(Status.running, Result.success),
216 const State(Status.complete, Result.success),
217 const State(Status.complete, Result.failure),
218 const State(Status.complete, Result.error)
219 ]);
220
221 expectErrors(liveTest, [(error) {
222 expect(lastState, equals(const State(Status.complete, Result.failure)));
223 expect(error, isTestFailure("oh no"));
224 }, (error) {
225 expect(lastState, equals(const State(Status.complete, Result.error)));
226 expect(error, equals(
227 "This test failed after it had already completed. Make sure to "
228 "use [expectAsync]\n"
229 "or the [completes] matcher when testing async code."));
230 }]);
231
232 return liveTest.run();
233 });
234
235 test("multiple asynchronous failures are reported", () {
236 var liveTest = new LocalTest("test", () {
237 Invoker.current.addOutstandingCallback();
238 new Future(() => throw new TestFailure("one"));
239 new Future(() => throw new TestFailure("two"));
240 new Future(() => throw new TestFailure("three"));
241 new Future(() => throw new TestFailure("four"));
242 }).load(suite);
243
244 expectStates(liveTest, [
245 const State(Status.running, Result.success),
246 const State(Status.complete, Result.failure)
247 ]);
248
249 expectErrors(liveTest, [(error) {
250 expect(lastState.status, equals(Status.complete));
251 expect(error, isTestFailure("one"));
252 }, (error) {
253 expect(error, isTestFailure("two"));
254 }, (error) {
255 expect(error, isTestFailure("three"));
256 }, (error) {
257 expect(error, isTestFailure("four"));
258 }]);
259
260 return liveTest.run();
261 });
262
263 test("a failure after an error doesn't change the state of the test", () {
264 var liveTest = new LocalTest("test", () {
265 new Future(() => throw new TestFailure("fail"));
266 throw "error";
267 }).load(suite);
268
269 expectStates(liveTest, [
270 const State(Status.running, Result.success),
271 const State(Status.complete, Result.error)
272 ]);
273
274 expectErrors(liveTest, [(error) {
275 expect(lastState, equals(const State(Status.complete, Result.error)));
276 expect(error, equals("error"));
277 }, (error) {
278 expect(error, isTestFailure("fail"));
279 }]);
280
281 return liveTest.run();
282 });
283
284 test("tearDown is run after an asynchronous failure", () {
285 var stateDuringTearDown;
286 var liveTest;
287 liveTest = new LocalTest("test", () {
288 Invoker.current.addOutstandingCallback();
289 new Future(() => throw new TestFailure("oh no"));
290 }, tearDown: () {
291 stateDuringTearDown = liveTest.state;
292 }).load(suite);
293
294 expectSingleFailure(liveTest);
295 return liveTest.run().then((_) {
296 expect(stateDuringTearDown,
297 equals(const State(Status.complete, Result.failure)));
298 });
299 });
300 });
301
302 group("in a test with errors,", () {
303 test("a synchronous throw is reported and causes the test to error", () {
304 var liveTest = new LocalTest("test", () {
305 throw 'oh no';
306 }).load(suite);
307
308 expectSingleError(liveTest);
309 return liveTest.run();
310 });
311
312 test("a synchronous reported error causes the test to error", () {
313 var liveTest = new LocalTest("test", () {
314 Invoker.current.handleError("oh no");
315 }).load(suite);
316
317 expectSingleError(liveTest);
318 return liveTest.run();
319 });
320
321 test("an error reported asynchronously during the test causes it to error",
322 () {
323 var liveTest = new LocalTest("test", () {
324 Invoker.current.addOutstandingCallback();
325 new Future(() => Invoker.current.handleError("oh no"));
326 }).load(suite);
327
328 expectSingleError(liveTest);
329 return liveTest.run();
330 });
331
332 test("an error thrown asynchronously during the test causes it to error",
333 () {
334 var liveTest = new LocalTest("test", () {
335 Invoker.current.addOutstandingCallback();
336 new Future(() => throw "oh no");
337 }).load(suite);
338
339 expectSingleError(liveTest);
340 return liveTest.run();
341 });
342
343 test("an error reported asynchronously after the test causes it to error",
344 () {
345 var liveTest = new LocalTest("test", () {
346 new Future(() => Invoker.current.handleError("oh no"));
347 }).load(suite);
348
349 expectStates(liveTest, [
350 const State(Status.running, Result.success),
351 const State(Status.complete, Result.success),
352 const State(Status.complete, Result.error)
353 ]);
354
355 expectErrors(liveTest, [(error) {
356 expect(lastState, equals(const State(Status.complete, Result.error)));
357 expect(error, equals("oh no"));
358 }, (error) {
359 expect(error, equals(
360 "This test failed after it had already completed. Make sure to "
361 "use [expectAsync]\n"
362 "or the [completes] matcher when testing async code."));
363 }]);
364
365 return liveTest.run();
366 });
367
368 test("multiple asynchronous errors are reported", () {
369 var liveTest = new LocalTest("test", () {
370 Invoker.current.addOutstandingCallback();
371 new Future(() => throw "one");
372 new Future(() => throw "two");
373 new Future(() => throw "three");
374 new Future(() => throw "four");
375 }).load(suite);
376
377 expectStates(liveTest, [
378 const State(Status.running, Result.success),
379 const State(Status.complete, Result.error)
380 ]);
381
382 expectErrors(liveTest, [(error) {
383 expect(lastState.status, equals(Status.complete));
384 expect(error, equals("one"));
385 }, (error) {
386 expect(error, equals("two"));
387 }, (error) {
388 expect(error, equals("three"));
389 }, (error) {
390 expect(error, equals("four"));
391 }]);
392
393 return liveTest.run();
394 });
395
396 test("an error after a failure changes the state of the test", () {
397 var liveTest = new LocalTest("test", () {
398 new Future(() => throw "error");
399 throw new TestFailure("fail");
400 }).load(suite);
401
402 expectStates(liveTest, [
403 const State(Status.running, Result.success),
404 const State(Status.complete, Result.failure),
405 const State(Status.complete, Result.error)
406 ]);
407
408 expectErrors(liveTest, [(error) {
409 expect(lastState, equals(const State(Status.complete, Result.failure)));
410 expect(error, isTestFailure("fail"));
411 }, (error) {
412 expect(lastState, equals(const State(Status.complete, Result.error)));
413 expect(error, equals("error"));
414 }]);
415
416 return liveTest.run();
417 });
418
419 test("tearDown is run after an asynchronous error", () {
420 var stateDuringTearDown;
421 var liveTest;
422 liveTest = new LocalTest("test", () {
423 Invoker.current.addOutstandingCallback();
424 new Future(() => throw "oh no");
425 }, tearDown: () {
426 stateDuringTearDown = liveTest.state;
427 }).load(suite);
428
429 expectSingleError(liveTest);
430 return liveTest.run().then((_) {
431 expect(stateDuringTearDown,
432 equals(const State(Status.complete, Result.error)));
433 });
434 });
435 });
436
437 test("a test doesn't complete until there are no outstanding callbacks",
438 () {
439 var outstandingCallbackRemoved = false;
440 var liveTest = new LocalTest("test", () {
441 Invoker.current.addOutstandingCallback();
442
443 // Pump the event queue to make sure the test isn't coincidentally
444 // completing after the outstanding callback is removed.
445 pumpEventQueue().then((_) {
446 outstandingCallbackRemoved = true;
447 Invoker.current.removeOutstandingCallback();
448 });
449 }).load(suite);
450
451 liveTest.onError.listen(expectAsync((_) {}, count: 0));
452
453 return liveTest.run().then((_) {
454 expect(outstandingCallbackRemoved, isTrue);
455 });
456 });
457
458 test("a test's tearDown isn't run until there are no outstanding callbacks",
459 () {
460 var outstandingCallbackRemoved = false;
461 var outstandingCallbackRemovedBeforeTeardown = false;
462 var liveTest = new LocalTest("test", () {
463 Invoker.current.addOutstandingCallback();
464 pumpEventQueue().then((_) {
465 outstandingCallbackRemoved = true;
466 Invoker.current.removeOutstandingCallback();
467 });
468 }, tearDown: () {
469 outstandingCallbackRemovedBeforeTeardown = outstandingCallbackRemoved;
470 }).load(suite);
471
472 liveTest.onError.listen(expectAsync((_) {}, count: 0));
473
474 return liveTest.run().then((_) {
475 expect(outstandingCallbackRemovedBeforeTeardown, isTrue);
476 });
477 });
478
479 test("a test times out after 30 seconds", () {
480 new FakeAsync().run((async) {
481 var liveTest = new LocalTest("test", () {
482 Invoker.current.addOutstandingCallback();
483 }).load(suite);
484
485 expectStates(liveTest, [
486 const State(Status.running, Result.success),
487 const State(Status.complete, Result.error)
488 ]);
489
490 expectErrors(liveTest, [(error) {
491 expect(lastState.status, equals(Status.complete));
492 expect(error, new isInstanceOf<TimeoutException>());
493 }]);
494
495 liveTest.run();
496 async.elapse(new Duration(seconds: 30));
497 });
498 });
499 }
500
501 /// Asserts that exactly [states] will be emitted via [liveTest.onStateChange].
502 ///
503 /// The most recent emitted state is stored in [lastState].
504 void expectStates(LiveTest liveTest, Iterable<State> states) {
kevmoo 2015/02/11 00:35:09 Make these helpers private
nweiz 2015/02/11 02:07:06 Done.
505 states = new Queue.from(states);
kevmoo 2015/02/11 01:18:28 Don't change the type of the var – the analyzer bo
nweiz 2015/02/11 02:07:06 Done.
506 liveTest.onStateChange.listen(expectAsync((state) {
507 lastState = state;
508 expect(state, equals(states.removeFirst()));
509 }, count: states.length, max: states.length));
510 }
511
512 /// Asserts that errors will be emitted via [liveTest.onError] that match
513 /// [validators], in order.
514 void expectErrors(LiveTest liveTest, Iterable<Function> validators) {
515 validators = new Queue.from(validators);
kevmoo 2015/02/11 01:18:28 Don't change the type of the var – the analyzer bo
nweiz 2015/02/11 02:07:06 Done.
516 liveTest.onError.listen(expectAsync((error) {
517 validators.removeFirst()(error.error);
518 }, count: validators.length, max: validators.length));
519 }
520
521 /// Asserts that [liveTest] will have a single failure with message `"oh no"`.
522 void expectSingleFailure(LiveTest liveTest) {
523 expectStates(liveTest, [
524 const State(Status.running, Result.success),
525 const State(Status.complete, Result.failure)
526 ]);
527
528 expectErrors(liveTest, [(error) {
529 expect(lastState.status, equals(Status.complete));
530 expect(error, isTestFailure("oh no"));
531 }]);
532 }
533
534 /// Asserts that [liveTest] will have a single error, the string `"oh no"`.
535 void expectSingleError(LiveTest liveTest) {
536 expectStates(liveTest, [
537 const State(Status.running, Result.success),
538 const State(Status.complete, Result.error)
539 ]);
540
541 expectErrors(liveTest, [(error) {
542 expect(lastState.status, equals(Status.complete));
543 expect(error, equals("oh no"));
544 }]);
545 }
OLDNEW
« lib/src/invoker.dart ('K') | « pubspec.yaml ('k') | test/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698