Dart Test Fundamentals

kevmoo/dash_skills/skills/dart-test-fundamentals

作者 kevmoo397a703060ec8449b4cee63749036f19662b1f0eApache-2.0收录于 2026年10月9日更新于 2026年10月9日

Core concepts and best practices for `package:test`. Covers `test`, `group`, lifecycle methods (`setUp`, `tearDown`), and configuration (`dart_test.yaml`).

AI 生成的概览

关于使用 package:test 组织、配置和清理 Dart 测试的指导。

功能
该技能记录了 Dart 的 package:test 的核心概念与最佳实践,涵盖 test 与 group 的结构、setUp、tearDown、setUpAll、tearDownAll 等生命周期方法、使用 addTearDown 清理资源,以及通过 dart_test.yaml 配置平台、标签和超时。它还涉及测试文件命名、测试接缝、真实实现与伪造对象、行为断言,以及常用的 dart test 命令。它仅提供说明,不生成文件或脚本。
适用场景
适用于编写新的 Dart 测试文件、用 group 组织测试套件、通过 dart_test.yaml 配置测试执行,或思考测试生命周期与资源清理时。它也说明了不适用的情况,例如对遗留单一 group 的改动、已迁移到 package:checks 的项目,以及没有共享状态的简单测试。
运行要求
不附带任何脚本或工具,仅为说明性内容。应用这些指导需要有一个使用 package:test 的 Dart 项目,文中还提到可选依赖,如 package:test_descriptor、package:http/testing.dart,以及用于浏览器测试的真实浏览器运行时。

Dart Test Fundamentals

When to use this skill

Use this skill when:

  • Writing new test files.
  • Structuring test suites with group.
  • Configuring test execution via dart_test.yaml.
  • Understanding test lifecycle methods.

When NOT to use (Abstention Guardrails)

Do NOT apply this skill or refactor existing tests when:

  • Legacy Single-Group Churn: Do NOT remove or reformat existing group hierarchies in untouched existing tests unless explicitly asked, as this causes unwanted diff churn.
  • Alternative Assertion Frameworks: The package has migrated to package:checks or a specialized testing framework; do not revert tests back to legacy package:matcher idioms.
  • Trivial Tests with Zero Setup: Simple standalone tests with no shared state or resources do not need group, setUp, or addTearDown. Do not add ceremonial wrapper boilerplate.

Discovery

To find candidates for improving test structure:

try-finally Cleanup

Search for tests that use try-finally for cleanup instead of addTearDown:

  • Regex: \bfinally\s*\{ (Check if this is used for resource cleanup inside a test).

Core Concepts

1. Test Structure (test and group)

  • test: The fundamental unit of testing.

    dart
    test('description', () {  // assertions});
  • group: Used to organize tests into logical blocks.

    • Groups can be nested.
    • Descriptions are concatenated (e.g., "Group Description Test Description").
    • Helps scope setUp and tearDown calls.
    • Naming: Use PascalCase for groups that correspond to a class name (e.g., group('MyClient', ...)).
    • Avoid Single Groups: Do not wrap all tests in a file with a single group call if it's the only one.
      • NOTE: DO NOT remove groups when doing a cleanup on existing code you didn't create unless explicitly asked to. This can cause a LOT of churn in the DIFF that most engineers won't want!
  • Naming Tests test('test name here',:

    • Avoid redundant "test" prefixes. Use group instead.
    • Include the expected behavior or outcome in the description (e.g., 'throws StateError' or 'adds API key to URL').
    • Descriptions should read well when concatenated with their group name.
  • Named Parameters Placement:

    • For test and group calls, place named parameters (e.g., testOn, timeout, skip) immediately after the description string, before the callback closure. This improves readability by keeping the test logic last.
      dart
      test('description', testOn: 'vm', () {  // assertions});

2. Lifecycle Methods (setUp, tearDown)

  • setUp: Runs before every test in the current group (and nested groups).
  • tearDown: Runs after every test in the current group.
  • setUpAll: Runs once before any test in the group.
  • tearDownAll: Runs once after all tests in the group.

Best Practice:

  • Use setUp for resetting state to ensure test isolation.
  • Avoid sharing mutable state between tests without resetting it.

3. Cleaning Up Resources

  • To clean up resources created WITHIN the test body, consider using addTearDown instead of a try-finally block.

Avoid:

dart
test('can create and delete a file', () {  final file = File('temp.txt');  try {    file.writeAsStringSync('hello');    expect(file.readAsStringSync(), 'hello');  } finally {    if (file.existsSync()) file.deleteSync();  }});

Prefer:

dart
test('can create and delete a file', () {  final file = File('temp.txt');  // Register teardown immediately after resource creation intent  addTearDown(() {    if (file.existsSync()) file.deleteSync();  });
  file.writeAsStringSync('hello');  expect(file.readAsStringSync(), 'hello');});

4. Configuration (dart_test.yaml)

The dart_test.yaml file configures the test runner. Common configurations include:

Platforms

Define where tests run (vm, chrome, node).

yaml
platforms:  - vm  - chrome
Tags

Categorize tests to run specific subsets.

yaml
tags:  integration:    timeout: 2x

Usage in code:

dart
@Tags(['integration'])import 'package:test/test.dart';

Running tags: dart test --tags integration

Timeouts

Set default timeouts for tests.

yaml
timeouts:  2x # Double the default timeout

5. File Naming

  • Test files must end in _test.dart to be picked up by the test runner.
  • Place tests in the test/ directory.

6. Test Design, Seams & Real Test Doubles

  • Test Seams (lib/<pkg>.dart vs. lib/src/):
    • Import package:<pkg>/<pkg>.dart for package-level and integration tests, keeping lib/<pkg>.dart exports strictly scoped to public consumers.
    • Import package:<pkg>/src/<subsystem>.dart directly when unit-testing an internal deep module (e.g., an unexported parser, state machine, or data structure with a simple interface and rich behavior), while testing thin single-caller helpers through their owning module's entrypoint.
  • Real Implementations & First-Party Fakes (Real -> Fake -> Stub):
    • Exercise real dependencies and first-party fakes so tests fail when production contracts change: use package:test_descriptor (d.sandbox, d.dir, d.file) or Directory.systemTemp.createTempSync() for filesystem I/O, in-memory stores or loopback HttpServer instances for services, package:http/testing.dart (MockClient) for HTTP, and hand-written fakes/stubs for custom interfaces.
    • Run browser, DOM, and JS/Wasm interop tests on a real browser runtime (@TestOn('browser')).
  • Behavioral & Execution-Driven Assertions:
    • Boundary & Consumer Behavior: Test the observable outputs and boundary conditions of functions that consume constants and models (e.g., validate('a' * 280) vs. validate('a' * 281)) against concrete expected values.
    • Direct Execution & Rendering: Verify runtime behavior, control flow, and UI/CLI output by invoking functions or rendering components directly. Use raw file-text reads (readAsStringSync()) specifically for static README.md --help drift checks, BUILD / pubspec.yaml metadata sync, and codegen fixtures.

Common commands

  • dart test: Run all tests.
  • dart test test/path/to/file_test.dart: Run a specific file.
  • dart test --name "substring": Run tests matching a description.

Related Skills

dart-test-fundamentals is the core skill for structuring and configuring tests. For writing assertions within those tests, refer to:

来源与署名

来源:kevmoo/dash_skills位于skills/dart-test-fundamentals提交397a703

许可证: Apache-2.0

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架