dart-checks-migration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Dart Checks Migration

Dart Checks 迁移指南

When to use this skill

何时使用此技能

Use this skill when:
  • Migrating existing test files from
    package:matcher
    to
    package:checks
    .
  • A user specifically asks for "modern checks" or similar.
在以下场景使用此技能:
  • 将现有测试文件从
    package:matcher
    迁移到
    package:checks
    时。
  • 用户明确要求“现代化检查”或类似需求时。

The Workflow

工作流程

  1. Analysis:
    • Use
      grep
      to identify files using
      expect
      or
      package:matcher
      .
    • Review custom matchers; these may require manual migration.
  2. Tools & Dependencies:
    • Ensure
      dev_dependencies
      includes
      checks
      .
    • Run
      dart pub add --dev checks
      if missing.
  3. Discovery:
    • Use the Strategies for Discovery below to find candidates.
  4. Replacement:
    • Add
      import 'package:checks/checks.dart';
      .
    • Apply the Common Patterns below.
    • Final Step: Replace
      import 'package:test/test.dart';
      with
      import 'package:test/scaffolding.dart';
      ONLY after all
      expect
      calls are replaced. This ensures incremental progress.
  5. Verification:
    • Ensure the code analyzes cleanly.
    • Ensure tests pass.
  1. 分析:
    • 使用
      grep
      识别使用
      expect
      package:matcher
      的文件。
    • 检查自定义匹配器;这些可能需要手动迁移。
  2. 工具与依赖:
    • 确保
      dev_dependencies
      中包含
      checks
    • 如果缺失,运行
      dart pub add --dev checks
  3. 发现候选:
    • 使用下方的发现策略找到需要迁移的代码。
  4. 替换操作:
    • 添加
      import 'package:checks/checks.dart';
    • 应用下方的常见模式进行替换。
    • 最后一步:仅在所有
      expect
      调用都替换完成后,将
      import 'package:test/test.dart';
      替换为
      import 'package:test/scaffolding.dart';
      。这可确保迁移过程逐步推进。
  5. 验证:
    • 确保代码能通过静态分析。
    • 确保测试用例全部通过。

Common Patterns

常见模式

Legacy
expect
Modern
check
expect(a, equals(b))
check(a).equals(b)
expect(a, isTrue)
check(a).isTrue()
expect(a, isFalse)
check(a).isFalse()
expect(a, isNull)
check(a).isNull()
expect(a, isNotNull)
check(a).isNotNull()
expect(() => fn(), throwsA<T>())
check(() => fn()).throws<T>()
expect(list, hasLength(n))
check(list).length.equals(n)
expect(a, closeTo(b, delta))
check(a).isA<num>().isCloseTo(b, delta)
expect(a, greaterThan(b))
check(a).isGreaterThan(b)
expect(a, lessThan(b))
check(a).isLessThan(b)
expect(list, isEmpty)
check(list).isEmpty()
expect(list, isNotEmpty)
check(list).isNotEmpty()
expect(list, contains(item))
check(list).contains(item)
expect(map, equals(otherMap))
check(map).deepEquals(otherMap)
expect(list, equals(otherList))
check(list).deepEquals(otherList)
expect(future, completes)
await check(future).completes()
expect(stream, emitsInOrder(...))
await check(stream).withQueue.inOrder(...)
旧版
expect
写法
新版
check
写法
expect(a, equals(b))
check(a).equals(b)
expect(a, isTrue)
check(a).isTrue()
expect(a, isFalse)
check(a).isFalse()
expect(a, isNull)
check(a).isNull()
expect(a, isNotNull)
check(a).isNotNull()
expect(() => fn(), throwsA<T>())
check(() => fn()).throws<T>()
expect(list, hasLength(n))
check(list).length.equals(n)
expect(a, closeTo(b, delta))
check(a).isA<num>().isCloseTo(b, delta)
expect(a, greaterThan(b))
check(a).isGreaterThan(b)
expect(a, lessThan(b))
check(a).isLessThan(b)
expect(list, isEmpty)
check(list).isEmpty()
expect(list, isNotEmpty)
check(list).isNotEmpty()
expect(list, contains(item))
check(list).contains(item)
expect(map, equals(otherMap))
check(map).deepEquals(otherMap)
expect(list, equals(otherList))
check(list).deepEquals(otherList)
expect(future, completes)
await check(future).completes()
expect(stream, emitsInOrder(...))
await check(stream).withQueue.inOrder(...)

Async & Futures (CRITICAL)

异步与Future(重点注意)

  • Checking async functions:
    check(() => asyncFunc()).throws<T>()
    causes FALSE POSITIVES because the closure returns a
    Future
    , which is a value, so it "completes normally" (as a Future). Correct Usage:
    dart
    await check(asyncFunc()).throws<T>();
  • Chaining on void returns: Many async check methods (like
    throws
    ) return
    Future<void>
    . You cannot chain directly on them. Use cascades or callbacks. Wrong:
    dart
    await check(future).throws<Error>().has((e) => e.message, 'message').equals('foo');
    Correct:
    dart
    await check(future).throws<Error>((it) => it.has((e) => e.message, 'message').equals('foo'));
  • 检查异步函数:
    check(() => asyncFunc()).throws<T>()
    会导致误判,因为闭包返回的是
    Future
    对象,它会“正常完成”(作为一个Future)。 正确用法:
    dart
    await check(asyncFunc()).throws<T>();
  • 无返回值的链式调用: 许多异步检查方法(如
    throws
    )返回
    Future<void>
    。你不能直接在它们后面链式调用其他方法。请使用级联操作或回调函数。 错误写法:
    dart
    await check(future).throws<Error>().has((e) => e.message, 'message').equals('foo');
    正确写法:
    dart
    await check(future).throws<Error>((it) => it.has((e) => e.message, 'message').equals('foo'));

Complex Examples

复杂示例

Deep Verification with
isA
and
having
:
Legacy:
dart
expect(() => foo(), throwsA(isA<ArgumentError>()
    .having((e) => e.message, 'message', contains('MSG'))));
Modern:
dart
check(() => foo())
    .throws<ArgumentError>()
    .has((e) => e.message, 'message')
    .contains('MSG');
Property Extraction:
Legacy:
dart
expect(obj.prop, equals(value)); // When checking multiple props
Modern:
dart
check(obj)
  ..has((e) => e.prop, 'prop').equals(value)
  ..has((e) => e.other, 'other').equals(otherValue);
One-line Cascades: Since checks often return
void
, use cascades for multiple assertions on the same subject.
dart
check(it)..isGreaterThan(10)..isLessThan(20);
使用
isA
having
进行深度验证:
旧版:
dart
expect(() => foo(), throwsA(isA<ArgumentError>()
    .having((e) => e.message, 'message', contains('MSG'))));
新版:
dart
check(() => foo())
    .throws<ArgumentError>()
    .has((e) => e.message, 'message')
    .contains('MSG');
属性提取:
旧版:
dart
expect(obj.prop, equals(value)); // 当检查多个属性时
新版:
dart
check(obj)
  ..has((e) => e.prop, 'prop').equals(value)
  ..has((e) => e.other, 'other').equals(otherValue);
单行级联调用: 由于check方法通常返回
void
,对同一对象进行多个断言时请使用级联操作。
dart
check(it)..isGreaterThan(10)..isLessThan(20);

Constraints

约束条件

  • Scope: Only modify files in
    test/
    (and
    pubspec.yaml
    ).
  • Correctness: One failing test is unacceptable. If a test fails after migration and you cannot fix it immediately, REVERT that specific change.
  • Type Safety:
    package:checks
    is stricter about types than
    matcher
    . You may need to add explicit
    as T
    casts or
    isA<T>()
    checks in the chain.
  • 范围:仅修改
    test/
    目录下的文件(以及
    pubspec.yaml
    )。
  • 正确性:不允许出现测试失败的情况。如果迁移后某个测试失败且无法立即修复,请撤销该特定修改
  • 类型安全
    package:checks
    在类型检查上比
    matcher
    更严格。你可能需要在链式调用中添加显式的
    as T
    类型转换或
    isA<T>()
    检查。