checks 0.2.0
checks: ^0.2.0 copied to clipboard
A framework for checking values against expectations and building custom expectations.
Checking expectations with checks #
Expectations start with check. This utility returns a Subject, and
expectations can be checked against the subject. Expectations are defined as
extension methods, and different expectations will be available for subjects
with different value types.
check(someValue).equals(expectedValue);
check(someList).deepEquals(expectedList);
check(someString).contains('expected pattern');
Multiple expectations can be checked against the same value using cascade syntax. When multiple expectations are checked against a single value, a failure will included descriptions of the expectations that already passed.
check(someString)
..startsWith('a')
..endsWith('z')
..contains('lmno');
Some expectations return a Subject for another value derived from the original
value - for instance reading a field or awaiting the result of a Future.
check(someString).length.equals(expectedLength);
(await check(someFuture).completes()).equals(expectedCompletion);
Fields can be extracted from objects for checking further properties with the
has utility.
check(someValue)
.has((value) => value.property, 'property')
.equals(expectedPropertyValue);
Some expectations take arguments which are themselves expectations to apply to
other values. These expectations take Condition arguments, which check
expectations when they are applied to a Subject. The ConditionSubject
utility acts as both a condition and a subject. Any expectations checked on the
value as a subject will be recorded and replayed when it is applied as a
condition. The it() utility returns a ConditionSubject.
check(someList).any(it()..isGreaterThan(0));
Some complicated checks may be not be possible to write with cascade syntax.
There is a which utility for this use case which takes a Condition.
check(someString)
..startsWith('a')
// A cascade would not be possible on `length`
..length.which(it()
..isGreatherThan(10)
..isLessThan(100));
Writing custom expectations #
Expectations are written as extension on Subject with specific generics. The
library package:checks/context.dart gives access to a context getter on
Subject which offers capabilities for defining expectations on the subject's
value.
The Context allows checking a expectation with expect, expectAsync and
expectUnawaited, or extracting a derived value for performing other checks
with nest and nestAsync. Failures are reported by returning a Rejection,
or an Extracted.rejection, extensions should avoid throwing exceptions.
Descriptions of the clause checked by an expectations are passed through a
separate callback from the predicate which checks the value. Nesting calls are
made with a label directly. When there are no failures the clause callbacks are
not called. When a Condition is described, the clause callbacks are called,
but the predicate callbacks are not called. Conditions can be checked against
values without throwing an exception using softCheck or softCheckAsync.
extension CustomChecks on Subject<CustomType> {
void someExpectation() {
context.expect(() => ['meets this expectation'], (actual) {
if (_expectationIsMet(actual)) return null;
return Rejection(which: ['does not meet this expectation']);
});
}
Subject<Foo> get someDerivedValue =>
context.nest(() => ['has someDerivedValue'], (actual) {
if (_cannotReadDerivedValue(actual)) {
return Extracted.rejection(which: ['cannot read someDerivedValue']);
}
return Extracted.value(_readDerivedValue(actual));
});
// for field reads that will not get rejected, use `has`
Subject<Bar> get someField => has((a) => a.someField, 'someField');
}