checks 0.1.0 copy "checks: ^0.1.0" to clipboard
checks: ^0.1.0 copied to clipboard

A framework for checking values against expectations and building custom expectations.

Checking expectations with checks #

Expectations start with checkThat. 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.

checkThat(someValue).equals(expectedValue);
checkThat(someList).deepEquals(expectedList);
checkThat(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.

checkThat(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.

checkThat(someString).length.equals(expectedLength);
(await checkThat(someFuture).completes()).equals(expectedCompletion);

Fields can be extracted from objects for checking further properties with the has utility.

checkThat(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.

checkThat(someList).any(it()..isGreaterThan(0));

Some complicated checks may be difficult to write with parenthesized awaited expressions, or impossible to write with cascade syntax. There are which utilities for both use cases which take a Condition.

checkThat(someString)
  ..startsWith('a')
  // A cascade would not be possible on `length`
  ..length.which(it()
    ..isGreatherThan(10)
    ..isLessThan(100));

await checkThat(someFuture)
    .completes()
    .which(it()..equals(expectedCompletion));

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');
}

Trying Checks as a Preview #

  1. Add a dev_dependency on checks: ^0.1.0.

  2. Replace the existing package:test/test.dart import with package:test/scaffolding.dart.

  3. Add an import to package:checks/checks.dart.

  4. For an incremental migration within the test, add an import to package:test/expect.dart. Remove it to surface errors in tests that still need to be migrated, or keep it in so the tests work without being fully migrated.

  5. Migrate the test cases.

Migrating from Matchers #

Replace calls to expect with a call to checkThat passing the first argument. When a direct replacement is available, change the second argument from calling a function returning a Matcher, to calling the extension method on the Subject.

When a non-matcher argument is used for the expected value, it would have been wrapped with equals automatically. See below, .equals may not always be the correct replacement in package:checks.

expect(actual, expected);
checkThat(actual).equals(expected);
// or maybe
checkThat(actual).deepEquals(expected);

Differences in behavior from matcher #

  • The equals Matcher performed a deep equality check on collections. .equals() expectation will only correspond to [operator ==] so some tests may need to replace .equals() with .deepEquals().
86
likes
0
pub points
77%
popularity

Publisher

verified publisherlabs.dart.dev

A framework for checking values against expectations and building custom expectations.

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

async, test_api

More

Packages that depend on checks