| Index: README.md
|
| diff --git a/README.md b/README.md
|
| index f9ff2f96a748421b70485c90d598389bc693d3bf..4dc8c02e38f8731fd2b2e36e8a27cfd87e882ff6 100644
|
| --- a/README.md
|
| +++ b/README.md
|
| @@ -1,141 +1,176 @@
|
| -Support for writing unit tests in Dart.
|
| +`unittest` provides a standard way of writing and running tests in Dart.
|
|
|
| -**See also:**
|
| -[Unit Testing with Dart]
|
| -(http://www.dartlang.org/articles/dart-unit-tests/)
|
| +## Writing Tests
|
|
|
| -##Concepts
|
| +Tests are specified using the top-level [`test()`][test] function, and test
|
| +assertions are made using [`expect()`][expect]:
|
|
|
| - * __Tests__: Tests are specified via the top-level function [test], they can be
|
| - organized together using [group].
|
| +[test]: http://www.dartdocs.org/documentation/unittest/latest/index.html#unittest/unittest@id_test
|
| +[expect]: http://www.dartdocs.org/documentation/unittest/latest/index.html#unittest/unittest@id_expect
|
|
|
| - * __Checks__: Test expectations can be specified via [expect]
|
| -
|
| - * __Matchers__: [expect] assertions are written declaratively using the
|
| - [Matcher] class.
|
| +```dart
|
| +import "package:unittest/unittest.dart";
|
|
|
| - * __Configuration__: The framework can be adapted by setting
|
| - [unittestConfiguration] with a [Configuration]. See the other libraries
|
| - in the `unittest` package for alternative implementations of
|
| - [Configuration] including `compact_vm_config.dart`, `html_config.dart`
|
| - and `html_enhanced_config.dart`.
|
| +void main() {
|
| + test("String.split() splits the string on the delimiter", () {
|
| + var string = "foo,bar,baz";
|
| + expect(string.split(","), equals(["foo", "bar", "baz"]));
|
| + });
|
|
|
| -##Examples
|
| + test("String.trim() removes surrounding whitespace", () {
|
| + var string = " foo ";
|
| + expect(string.trim(), equals("foo"));
|
| + });
|
| +}
|
| +```
|
|
|
| -A trivial test:
|
| +Tests can be grouped together using the [`group()`] function. Each group's
|
| +description is added to the beginning of its test's descriptions.
|
|
|
| ```dart
|
| -import 'package:unittest/unittest.dart';
|
| +import "package:unittest/unittest.dart";
|
|
|
| void main() {
|
| - test('this is a test', () {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| + group("String", () {
|
| + test(".split() splits the string on the delimiter", () {
|
| + var string = "foo,bar,baz";
|
| + expect(string.split(","), equals(["foo", "bar", "baz"]));
|
| + });
|
| +
|
| + test(".trim() removes surrounding whitespace", () {
|
| + var string = " foo ";
|
| + expect(string.trim(), equals("foo"));
|
| + });
|
| + });
|
| +
|
| + group("int", () {
|
| + test(".remainder() returns the remainder of division", () {
|
| + expect(11.remainder(3), equals(2));
|
| + });
|
| +
|
| + test(".toRadixString() returns a hex string", () {
|
| + expect(11.toRadixString(16), equals("b"));
|
| + });
|
| });
|
| }
|
| ```
|
|
|
| -Multiple tests:
|
| +Any matchers from the [`matcher`][matcher] package can be used with `expect()`
|
| +to do complex validations:
|
| +
|
| +[matcher]: http://www.dartdocs.org/documentation/matcher/latest/index.html#matcher/matcher
|
|
|
| ```dart
|
| -import 'package:unittest/unittest.dart';
|
| +import "package:unittest/unittest.dart";
|
|
|
| void main() {
|
| - test('this is a test', () {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| - });
|
| - test('this is another test', () {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| + test(".split() splits the string on the delimiter", () {
|
| + expect("foo,bar,baz", allOf([
|
| + contains("foo"),
|
| + isNot(startsWith("bar")),
|
| + endsWith("baz")
|
| + ]));
|
| });
|
| }
|
| ```
|
|
|
| -Multiple tests, grouped by category:
|
| +## Running Tests
|
| +
|
| +A single test file can be run just using `dart path/to/test.dart`.
|
| +
|
| +
|
| +
|
| +Many tests can be run at a time using `pub run unittest:unittest path/to/dir`.
|
| +
|
| +
|
| +
|
| +`unittest` considers any file that ends with `_test.dart` to be a test file. If
|
| +you don't pass any paths, it will run all the test files in your `test/`
|
| +directory, making it easy to test your entire application at once.
|
| +
|
| +By default, tests are run in the Dart VM, but you can run them in the browser as
|
| +well by passing `pub run unittest:unittest -p chrome path/to/test.dart`.
|
| +`unittest` will take care of starting the browser and loading the tests, and all
|
| +the results will be reported on the command line just like for VM tests. In
|
| +fact, you can even run tests on both platforms with a single command: `pub run
|
| +unittest:unittest -p chrome -p vm path/to/test.dart`.
|
| +
|
| +## Asynchronous Tests
|
| +
|
| +Tests written with `async`/`await` will work automatically. The test runner
|
| +won't consider the test finished until the returned `Future` completes.
|
|
|
| ```dart
|
| -import 'package:unittest/unittest.dart';
|
| +import "dart:async";
|
| +
|
| +import "package:unittest/unittest.dart";
|
|
|
| void main() {
|
| - group('group A', () {
|
| - test('test A.1', () {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| - });
|
| - test('test A.2', () {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| - });
|
| - });
|
| - group('group B', () {
|
| - test('this B.1', () {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| - });
|
| + test("new Future.value() returns the value", () async {
|
| + var value = await new Future.value(10);
|
| + expect(value, equals(10));
|
| });
|
| }
|
| ```
|
|
|
| -Asynchronous tests: if callbacks expect between 0 and 6 positional
|
| -arguments, [expectAsync] will wrap a function into a new callback and will
|
| -not consider the test complete until that callback is run. A count argument
|
| -can be provided to specify the number of times the callback should be called
|
| -(the default is 1).
|
| +There are also a number of useful functions and matchers for more advanced
|
| +asynchrony. The [`completion()`][completion] matcher can be used to test
|
| +`Futures`; it ensures that the test doesn't finish until the `Future` completes,
|
| +and runs a matcher against that `Future`'s value.
|
| +
|
| +[completion]: http://www.dartdocs.org/documentation/unittest/latest/index.html#unittest/unittest@id_completion
|
|
|
| ```dart
|
| -import 'dart:async';
|
| -import 'package:unittest/unittest.dart';
|
| +import "dart:async";
|
|
|
| -void main() {
|
| - test('callback is executed once', () {
|
| - // wrap the callback of an asynchronous call with [expectAsync] if
|
| - // the callback takes 0 arguments...
|
| - Timer.run(expectAsync(() {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| - }));
|
| - });
|
| +import "package:unittest/unittest.dart";
|
|
|
| - test('callback is executed twice', () {
|
| - var callback = expectAsync(() {
|
| - int x = 2 + 3;
|
| - expect(x, equals(5));
|
| - }, count: 2); // <-- we can indicate multiplicity to [expectAsync]
|
| - Timer.run(callback);
|
| - Timer.run(callback);
|
| +void main() {
|
| + test("new Future.value() returns the value", () {
|
| + expect(new Future.value(10), completion(equals(10)));
|
| });
|
| }
|
| ```
|
|
|
| -There may be times when the number of times a callback should be called is
|
| -non-deterministic. In this case a dummy callback can be created with
|
| -expectAsync((){}) and this can be called from the real callback when it is
|
| -finally complete.
|
| -
|
| -A variation on this is [expectAsyncUntil], which takes a callback as the
|
| -first parameter and a predicate function as the second parameter. After each
|
| -time the callback is called, the predicate function will be called. If it
|
| -returns `false` the test will still be considered incomplete.
|
| +The [`throwsA()`][throwsA] matcher and the various `throwsExceptionType`
|
| +matchers work with both synchronous callbacks and asynchronous `Future`s. They
|
| +ensure that a particular type of exception is thrown:
|
|
|
| -Test functions can return [Future]s, which provide another way of doing
|
| -asynchronous tests. The test framework will handle exceptions thrown by
|
| -the Future, and will advance to the next test when the Future is complete.
|
| +[completion]: http://www.dartdocs.org/documentation/unittest/latest/index.html#unittest/unittest@id_throwsA
|
|
|
| ```dart
|
| -import 'dart:async';
|
| -import 'package:unittest/unittest.dart';
|
| +import "dart:async";
|
| +
|
| +import "package:unittest/unittest.dart";
|
|
|
| void main() {
|
| - test('test that time has passed', () {
|
| - var duration = const Duration(milliseconds: 200);
|
| - var time = new DateTime.now();
|
| + test("new Future.error() throws the error", () {
|
| + expect(new Future.error("oh no"), throwsA(equals("oh no")));
|
| + expect(new Future.error(new StateError("bad state")), throwsStateError);
|
| + });
|
| +}
|
| +```
|
|
|
| - return new Future.delayed(duration).then((_) {
|
| - var delta = new DateTime.now().difference(time);
|
| +The [`expectAsync()`][expectAsync] function wraps another function and has two
|
| +jobs. First, it asserts that the wrapped function is called a certain number of
|
| +times, and will cause the test to fail if it's called too often; second, it
|
| +keeps the test from finishing until the function is called the requisite number
|
| +of times.
|
|
|
| - expect(delta, greaterThanOrEqualTo(duration));
|
| - });
|
| +```dart
|
| +import "dart:async";
|
| +
|
| +import "package:unittest/unittest.dart";
|
| +
|
| +void main() {
|
| + test("Stream.fromIterable() emits the values in the iterable", () {
|
| + var stream = new Stream.fromIterable([1, 2, 3]);
|
| +
|
| + stream.listen(expectAsync((number) {
|
| + expect(number, inInclusiveRange(1, 3));
|
| + }, count: 3));
|
| });
|
| }
|
| ```
|
| +
|
| +[expectAsync]: http://www.dartdocs.org/documentation/unittest/latest/index.html#unittest/unittest@id_expectAsync
|
|
|