Last updated:
0 purchases
matcher
Support for specifying test expectations, such as for unit tests.
The matcher library provides a third-generation assertion mechanism, drawing
inspiration from Hamcrest.
For more information on testing, see
Unit Testing with Dart.
Using matcher #
Expectations start with a call to expect() or expectAsync().
Any matchers package can be used with expect() to do
complex validations:
import 'package:test/test.dart';
void main() {
test('.split() splits the string on the delimiter', () {
expect('foo,bar,baz', allOf([
contains('foo'),
isNot(startsWith('bar')),
endsWith('baz')
]));
});
}
copied to clipboard
If a non-matcher value is passed, it will be wrapped with equals().
Exception matchers #
You can also test exceptions with the throwsA() function or a matcher such
as throwsFormatException:
import 'package:test/test.dart';
void main() {
test('.parse() fails on invalid input', () {
expect(() => int.parse('X'), throwsFormatException);
});
}
copied to clipboard
Future Matchers #
There are a number of useful functions and matchers for more advanced
asynchrony. The 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.
import 'dart:async';
import 'package:test/test.dart';
void main() {
test('Future.value() returns the value', () {
expect(Future.value(10), completion(equals(10)));
});
}
copied to clipboard
The throwsA() matcher and the various throwsExceptionType matchers work
with both synchronous callbacks and asynchronous Futures. They ensure that a
particular type of exception is thrown:
import 'dart:async';
import 'package:test/test.dart';
void main() {
test('Future.error() throws the error', () {
expect(Future.error('oh no'), throwsA(equals('oh no')));
expect(Future.error(StateError('bad state')), throwsStateError);
});
}
copied to clipboard
The 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.
import 'dart:async';
import 'package:test/test.dart';
void main() {
test('Stream.fromIterable() emits the values in the iterable', () {
var stream = Stream.fromIterable([1, 2, 3]);
stream.listen(expectAsync1((number) {
expect(number, inInclusiveRange(1, 3));
}, count: 3));
});
}
copied to clipboard
Stream Matchers #
The test package provides a suite of powerful matchers for dealing with
asynchronous streams. They're expressive and composable, and make it
easy to write complex expectations about the values emitted by a stream. For
example:
import 'dart:async';
import 'package:test/test.dart';
void main() {
test('process emits status messages', () {
// Dummy data to mimic something that might be emitted by a process.
var stdoutLines = Stream.fromIterable([
'Ready.',
'Loading took 150ms.',
'Succeeded!'
]);
expect(stdoutLines, emitsInOrder([
// Values match individual events.
'Ready.',
// Matchers also run against individual events.
startsWith('Loading took'),
// Stream matchers can be nested. This asserts that one of two events are
// emitted after the "Loading took" line.
emitsAnyOf(['Succeeded!', 'Failed!']),
// By default, more events are allowed after the matcher finishes
// matching. This asserts instead that the stream emits a done event and
// nothing else.
emitsDone
]));
});
}
copied to clipboard
A stream matcher can also match the async package's StreamQueue class,
which allows events to be requested from a stream rather than pushed to the
consumer. The matcher will consume the matched events, but leave the rest of the
queue alone so that it can still be used by the test, unlike a normal Stream
which can only have one subscriber. For example:
import 'dart:async';
import 'package:async/async.dart';
import 'package:test/test.dart';
void main() {
test('process emits a WebSocket URL', () async {
// Wrap the Stream in a StreamQueue so that we can request events.
var stdout = StreamQueue(Stream.fromIterable([
'WebSocket URL:',
'ws://localhost:1234/',
'Waiting for connection...'
]));
// Ignore lines from the process until it's about to emit the URL.
await expectLater(stdout, emitsThrough('WebSocket URL:'));
// Parse the next line as a URL.
var url = Uri.parse(await stdout.next);
expect(url.host, equals('localhost'));
// You can match against the same StreamQueue multiple times.
await expectLater(stdout, emits('Waiting for connection...'));
});
}
copied to clipboard
The following built-in stream matchers are available:
emits() matches a single data event.
emitsError() matches a single error event.
emitsDone matches a single done event.
mayEmit() consumes events if they match an inner matcher, without
requiring them to match.
mayEmitMultiple() works like mayEmit(), but it matches events against
the matcher as many times as possible.
emitsAnyOf() consumes events matching one (or more) of several possible
matchers.
emitsInOrder() consumes events matching multiple matchers in a row.
emitsInAnyOrder() works like emitsInOrder(), but it allows the
matchers to match in any order.
neverEmits() matches a stream that finishes without matching an inner
matcher.
You can also define your own custom stream matchers with StreamMatcher().
Best Practices #
Prefer semantically meaningful matchers to comparing derived values #
Matchers which have knowledge of the semantics that are tested are able to emit
more meaningful messages which don't require reading test source to understand
why the test failed. For instance compare the failures between
expect(someList.length, 1), and expect(someList, hasLength(1)):
// expect(someList.length, 1);
Expected: <1>
Actual: <2>
copied to clipboard
// expect(someList, hasLength(1));
Expected: an object with length of <1>
Actual: ['expected value', 'unexpected value']
Which: has length of <2>
copied to clipboard
Prefer TypeMatcher to predicate if the match can fail in multiple ways #
The predicate utility is a convenient shortcut for testing an arbitrary
(synchronous) property of a value, but it discards context and failures are
opaque. Different failure modes cannot be distinguished in the output which is
determined by a single "description" argument. Using isA<SomeType>() and the
TypeMatcher.having API to extract and test derived properties in a structured
way brings the context of that structure through to failure messages, so
failures for different reasons will have distinguishable and actionable failure
messages.
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.