Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 * A library for writing dart unit tests. | 6 * A library for writing dart unit tests. |
| 7 * | 7 * |
| 8 * To import this library, specify the relative path to | 8 * To import this library, specify the relative path to |
| 9 * lib/unittest/unittest.dart. | 9 * lib/unittest/unittest.dart. |
| 10 * | 10 * |
| 11 * ##Concepts## | 11 * ##Concepts## |
| 12 * | 12 * |
| 13 * * Tests: Tests are specified via the top-level function [test], they can be | 13 * * Tests: Tests are specified via the top-level function [test], they can be |
| 14 * organized together using [group]. | 14 * organized together using [group]. |
| 15 * * Checks: Test expectations can be specified via [expect] (see methods in | 15 * * Checks: Test expectations can be specified via [expect] (see methods in |
| 16 * [Expectation]), [expectThrow], or using assertions with the [Expect] | 16 * [Expectation]), [expectThrow], or using assertions with the [Expect] |
| 17 * class. | 17 * class. |
| 18 * * Configuration: The framework can be adapted by calling [configure] with a | 18 * * Configuration: The framework can be adapted by calling [configure] with a |
| 19 * [Configuration]. Common configurations can be found in this package | 19 * [Configuration]. Common configurations can be found in this package |
| 20 * under: 'dom\_config.dart', 'html\_config.dart', and 'vm\_config.dart'. | 20 * under: 'dom\_config.dart' (deprecated), 'html\_config.dart' (for running |
| 21 * tests compiled to Javascript in a browser), and 'vm\_config.dart' (for | |
| 22 * running native Dart tests on the VM). | |
| 21 * | 23 * |
| 22 * ##Examples## | 24 * ##Examples## |
| 23 * | 25 * |
| 24 * A trivial test: | 26 * A trivial test: |
| 25 * | 27 * |
| 26 * #import('path-to-dart/lib/unittest/unitest.dart'); | 28 * #import('path-to-dart/lib/unittest/unitest.dart'); |
| 27 * main() { | 29 * main() { |
| 28 * test('this is a test', () { | 30 * test('this is a test', () { |
| 29 * int x = 2 + 3; | 31 * int x = 2 + 3; |
| 30 * expect(x).equals(5); | 32 * expect(x).equals(5); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 60 * }); | 62 * }); |
| 61 * }); | 63 * }); |
| 62 * group('group B', () { | 64 * group('group B', () { |
| 63 * test('this B.1', () { | 65 * test('this B.1', () { |
| 64 * int x = 2 + 3; | 66 * int x = 2 + 3; |
| 65 * expect(x).equals(5); | 67 * expect(x).equals(5); |
| 66 * }); | 68 * }); |
| 67 * }); | 69 * }); |
| 68 * } | 70 * } |
| 69 * | 71 * |
| 70 * Asynchronous tests: if callbacks expect between 0 and 2 positional arguments. | 72 * Asynchronous tests: if callbacks expect between 0 and 2 positional arguments, |
| 73 * depending on the suffix of expectAsyncX(). expectAsyncX() will wrap a functio n | |
|
Emily Fortuna
2012/05/31 17:09:28
Char > 80 here on this line and below.
gram
2012/05/31 17:38:42
Done.
| |
| 74 * into a new callback and will not consider the test complete until that callba ck | |
| 75 * is run. A count argument can be provided to specify the number of times the | |
| 76 * callback should be called (the default is 1). | |
| 71 * | 77 * |
| 72 * #import('path-to-dart/lib/unittest/unitest.dart'); | 78 * #import('path-to-dart/lib/unittest/unitest.dart'); |
| 73 * #import('dart:dom_deprecated'); | 79 * #import('dart:dom_deprecated'); |
| 74 * main() { | 80 * main() { |
| 75 * test('calllback is executed once', () { | 81 * test('calllback is executed once', () { |
| 76 * // wrap the callback of an asynchronous call with [expectAsync0] if | 82 * // wrap the callback of an asynchronous call with [expectAsync0] if |
| 77 * // the callback takes 0 arguments... | 83 * // the callback takes 0 arguments... |
| 78 * window.setTimeout(expectAsync0(() { | 84 * window.setTimeout(expectAsync0(() { |
| 79 * int x = 2 + 3; | 85 * int x = 2 + 3; |
| 80 * expect(x).equals(5); | 86 * expect(x).equals(5); |
| 81 * }), 0); | 87 * }), 0); |
| 82 * }); | 88 * }); |
| 83 * | 89 * |
| 84 * test('calllback is executed twice', () { | 90 * test('calllback is executed twice', () { |
| 85 * var callback = expectAsync0(() { | 91 * var callback = expectAsync0(() { |
| 86 * int x = 2 + 3; | 92 * int x = 2 + 3; |
| 87 * expect(x).equals(5); | 93 * expect(x).equals(5); |
| 88 * }, count: 2); // <-- we can indicate multiplicity to [expectAsync0] | 94 * }, count: 2); // <-- we can indicate multiplicity to [expectAsync0] |
| 89 * window.setTimeout(callback, 0); | 95 * window.setTimeout(callback, 0); |
| 90 * window.setTimeout(callback, 0); | 96 * window.setTimeout(callback, 0); |
| 91 * }); | 97 * }); |
| 92 * } | 98 * } |
| 93 * | 99 * |
| 100 * expectAsyncX() will wrap the callback code in a try/catch handler to handle | |
| 101 * exceptions (treated as test failures). There may be times when the number of | |
| 102 * times a callback should be called is non-deterministic. In this case a dummy | |
| 103 * callback can be created with expectAsync0((){}) and this can be called from | |
| 104 * the real callback when it is finally complete. In this case the body of the | |
| 105 * callback should be protected within a call to guardAsync(); this will ensure | |
| 106 * that exceptions are properly handled. | |
| 107 * | |
| 94 * Note: due to some language limitations we have to use different functions | 108 * Note: due to some language limitations we have to use different functions |
| 95 * depending on the number of positional arguments of the callback. In the | 109 * depending on the number of positional arguments of the callback. In the |
| 96 * future, we plan to expose a single `expectAsync` function that can be used | 110 * future, we plan to expose a single `expectAsync` function that can be used |
| 97 * regardless of the number of positional arguments. This requires new langauge | 111 * regardless of the number of positional arguments. This requires new langauge |
| 98 * features or fixes to the current spec (e.g. see | 112 * features or fixes to the current spec (e.g. see |
| 99 * [Issue 2706](http://dartbug.com/2706)). | 113 * [Issue 2706](http://dartbug.com/2706)). |
| 100 * | 114 * |
| 101 * Meanwhile, we plan to add this alternative API for callbacks of more than 2 | 115 * Meanwhile, we plan to add this alternative API for callbacks of more than 2 |
| 102 * arguments or that take named parameters. (this is not implemented yet, | 116 * arguments or that take named parameters. (this is not implemented yet, |
| 103 * but will be coming here soon). | 117 * but will be coming here soon). |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 215 * description will include the descriptions of any surrounding group() | 229 * description will include the descriptions of any surrounding group() |
| 216 * calls. | 230 * calls. |
| 217 */ | 231 */ |
| 218 void test(String spec, TestFunction body) { | 232 void test(String spec, TestFunction body) { |
| 219 ensureInitialized(); | 233 ensureInitialized(); |
| 220 | 234 |
| 221 _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0)); | 235 _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0)); |
| 222 } | 236 } |
| 223 | 237 |
| 224 /** | 238 /** |
| 225 * Creates a new async test case with the given description and body. The | |
| 226 * description will include the descriptions of any surrounding group() | |
| 227 * calls. | |
| 228 */ | |
| 229 // TODO(sigmund): deprecate this API | |
| 230 void asyncTest(String spec, int callbacks, TestFunction body) { | |
| 231 ensureInitialized(); | |
| 232 | |
| 233 final testCase = new TestCase( | |
| 234 _tests.length + 1, _fullSpec(spec), body, callbacks); | |
| 235 _tests.add(testCase); | |
| 236 | |
| 237 if (callbacks < 1) { | |
| 238 testCase.error( | |
| 239 'Async tests must wait for at least one callback ', ''); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 /** | |
| 244 * Creates a new test case with the given description and body. The | 239 * Creates a new test case with the given description and body. The |
| 245 * description will include the descriptions of any surrounding group() | 240 * description will include the descriptions of any surrounding group() |
| 246 * calls. | 241 * calls. |
| 247 * | 242 * |
| 248 * "solo_" means that this will be the only test that is run. All other tests | 243 * "solo_" means that this will be the only test that is run. All other tests |
| 249 * will be skipped. This is a convenience function to let you quickly isolate | 244 * will be skipped. This is a convenience function to let you quickly isolate |
| 250 * a single test by adding "solo_" before it to temporarily disable all other | 245 * a single test by adding "solo_" before it to temporarily disable all other |
| 251 * tests. | 246 * tests. |
| 252 */ | 247 */ |
| 253 void solo_test(String spec, TestFunction body) { | 248 void solo_test(String spec, TestFunction body) { |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 398 } | 393 } |
| 399 | 394 |
| 400 try { | 395 try { |
| 401 body(); | 396 body(); |
| 402 } finally { | 397 } finally { |
| 403 // Now that the group is over, restore the previous one. | 398 // Now that the group is over, restore the previous one. |
| 404 _currentGroup = oldGroup; | 399 _currentGroup = oldGroup; |
| 405 } | 400 } |
| 406 } | 401 } |
| 407 | 402 |
| 408 /** Called by subclasses to indicate that an asynchronous test completed. */ | 403 /* Called by subclasses to indicate that an asynchronous test completed. */ |
|
Emily Fortuna
2012/05/31 17:09:28
Put the other * back, please.
gram
2012/05/31 17:38:42
Done.
| |
| 409 void callbackDone() { | 404 void callbackDone() { |
| 410 // TODO (gram): we defer this to give the nextBatch recursive | 405 // TODO (gram): we defer this to give the nextBatch recursive |
| 411 // stack a chance to unwind. This is a temporary hack but | 406 // stack a chance to unwind. This is a temporary hack but |
| 412 // really a bunch of code here needs to be fixed. We have a | 407 // really a bunch of code here needs to be fixed. We have a |
| 413 // single array that is being iterated through by nextBatch(), | 408 // single array that is being iterated through by nextBatch(), |
| 414 // which is recursively invoked in the case of async tests that | 409 // which is recursively invoked in the case of async tests that |
| 415 // run synchronously. Bad things can then happen. | 410 // run synchronously. Bad things can then happen. |
| 416 _defer(() { | 411 _defer(() { |
| 417 _callbacksCalled++; | 412 _callbacksCalled++; |
| 418 if (_currentTest < _tests.length) { | 413 if (_currentTest < _tests.length) { |
| 419 final testCase = _tests[_currentTest]; | 414 final testCase = _tests[_currentTest]; |
| 420 if (_callbacksCalled > testCase.callbacks) { | 415 if (_callbacksCalled > testCase.callbacks) { |
| 421 final expected = testCase.callbacks; | 416 final expected = testCase.callbacks; |
| 422 testCase.error( | 417 testCase.error( |
| 423 'More calls to callbackDone() than expected. ' | 418 'More calls to callbackDone() than expected. ' |
| 424 'Actual: ${_callbacksCalled}, expected: ${expected}', ''); | 419 'Actual: ${_callbacksCalled}, expected: ${expected}', ''); |
| 425 _state = _UNCAUGHT_ERROR; | 420 _state = _UNCAUGHT_ERROR; |
| 426 } else if ((_callbacksCalled == testCase.callbacks) && | 421 } else if ((_callbacksCalled == testCase.callbacks) && |
| 427 (_state != _RUNNING_TEST)) { | 422 (_state != _RUNNING_TEST)) { |
| 428 if (testCase.result == null) testCase.pass(); | 423 if (testCase.result == null) testCase.pass(); |
| 429 _currentTest++; | 424 _currentTest++; |
| 430 _testRunner(); | 425 _testRunner(); |
| 431 } | 426 } |
| 432 } | 427 } |
| 433 }); | 428 }); |
| 434 } | 429 } |
| 435 | 430 |
| 436 /** Menchanism to notify that an error was caught outside of this library. */ | 431 /** Utility function that can be used to notify the test framework that an |
|
Emily Fortuna
2012/05/31 17:09:28
If the comment spans multiple lines, make the firs
gram
2012/05/31 17:38:42
Done.
| |
| 432 * error was caught outside of this library. | |
| 433 */ | |
| 437 void reportTestError(String msg, String trace) { | 434 void reportTestError(String msg, String trace) { |
| 438 if (_currentTest < _tests.length) { | 435 if (_currentTest < _tests.length) { |
| 439 final testCase = _tests[_currentTest]; | 436 final testCase = _tests[_currentTest]; |
| 440 testCase.error(msg, trace); | 437 testCase.error(msg, trace); |
| 441 _state = _UNCAUGHT_ERROR; | 438 _state = _UNCAUGHT_ERROR; |
| 442 if (testCase.callbacks > 0) { | 439 if (testCase.callbacks > 0) { |
| 443 _currentTest++; | 440 _currentTest++; |
| 444 _testRunner(); | 441 _testRunner(); |
| 445 } | 442 } |
| 446 } else { | 443 } else { |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 580 } | 577 } |
| 581 _config.onInit(); | 578 _config.onInit(); |
| 582 | 579 |
| 583 // Immediately queue the suite up. It will run after a timeout (i.e. after | 580 // Immediately queue the suite up. It will run after a timeout (i.e. after |
| 584 // main() has returned). | 581 // main() has returned). |
| 585 _defer(_runTests); | 582 _defer(_runTests); |
| 586 } | 583 } |
| 587 | 584 |
| 588 /** Signature for a test function. */ | 585 /** Signature for a test function. */ |
| 589 typedef void TestFunction(); | 586 typedef void TestFunction(); |
| OLD | NEW |