mcpField
D
dart-test-fundamentals

dart-test-fundamentals

github.com/kevmooテスト・品質148450 回インストール2 週間前に更新
リポジトリ

dart-test-fundamentals について

dart-test-fundamentalsは、Dart開発者向けにテストの構成と設定を案内するスキルです。テスト構造、ライフサイクル、後処理を扱い、規約を適用しない場面も示します。

主な機能

  1. 01testとgroupによるテスト構成
  2. 02setUpとtearDownのライフサイクル適用
  3. 03プラットフォーム、タグ、タイムアウトの設定
  4. 04リソース後処理とテストダブルの利用
  5. 05アサーションとテストシームの指針

活用シーン

  1. 01Dartテストスイートの作成や整理
  2. 02dart_test.yamlでのテスト実行設定
  3. 03テストリソースの後処理方法の選択

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kevmoo/dash_skills --skill dart-test-fundamentals

インストール後、Claude Code で/dart-test-fundamentalsを入力して読み込まれたか確認します。

同梱ファイルevals/evals.json

詳細

Dart テストの基礎

このスキルを使う場面

次のような場合にこのスキルを使います。

  • 新しいテストファイルを作成するとき。
  • group を使ってテストスイートを構成するとき。
  • dart_test.yaml でテストの実行を設定するとき。
  • テストのライフサイクルメソッドを理解するとき。
使わない場面(適用を控える基準)

次のような場合は、このスキルを適用したり、既存のテストをリファクタリングしたりしないでください。

  • 単一グループを使ったレガシーコードの変更:明示的に依頼されない限り、手を加えていない既存のテストから group の階層を削除したり、書式を変更したりしないでください。差分が不必要に増える原因になります。
  • 別のアサーションフレームワーク:パッケージが package:checks または専用のテストフレームワークに移行済みの場合、テストをレガシーな package:matcher のイディオムに戻さないでください。
  • セットアップ不要の簡単なテスト:共有状態やリソースのない単純な独立テストには、group、setUp、addTearDown は不要です。形式だけのラッパーを追加しないでください。

検出方法

テスト構成の改善候補を見つけるには、次の方法を使います。

try-finally によるクリーンアップ

addTearDown の代わりに try-finally でクリーンアップしているテストを検索します。

  • 正規表現:\bfinally\s*\{(テスト内でリソースのクリーンアップに使われているか確認します)。

基本概念

1. テスト構成(test と group)
  • test:テストの基本単位です。

    test('description', () {
      // assertions
    });
    
  • group:テストを論理的なまとまりに整理するために使います。

    • グループは入れ子にできます。
    • 説明は連結されます(例:「グループの説明 テストの説明」)。
    • setUp と tearDown の呼び出し範囲を指定できます。
    • 命名:クラス名に対応するグループには PascalCase を使います(例:group('MyClient', ...))。
    • 単一のグループを避ける:ファイル内のすべてのテストを囲む group 呼び出しがそれだけの場合は、追加しないでください。
      • 注:自分が作成していない既存コードをクリーンアップする際、明示的に依頼されない限りグループを削除しないでください。差分が大幅に増え、ほとんどのエンジニアにとって望ましくない結果になる可能性があります。
  • テストの命名 test('ここにテスト名',:

    • 「test」のような冗長な接頭辞は避けてください。代わりに group を使います。
    • 期待される動作や結果を説明に含めてください(例:'throws StateError'、'adds API key to URL')。
    • グループ名と連結したときに、自然に読める説明にしてください。
  • 名前付きパラメーターの配置:

    • test と group の呼び出しでは、名前付きパラメーター(例:testOn、timeout、skip)を説明文字列の直後、コールバックのクロージャーより前に配置してください。テストロジックを最後に置くことで、可読性が向上します。
      test('description', testOn: 'vm', () {
        // assertions
      });
      
2. ライフサイクルメソッド(setUp、tearDown)
  • setUp:現在の group(および入れ子のグループ)にある各 test の_前_に実行されます。
  • tearDown:現在の group にある各 test の_後_に実行されます。
  • setUpAll:グループ内のテストが始まる_前_に1回実行されます。
  • tearDownAll:グループ内のすべてのテストが終わった_後_に1回実行されます。

ベストプラクティス:

  • テストの分離性を確保するため、状態のリセットには setUp を使います。
  • リセットせずにテスト間で変更可能な状態を共有しないでください。
3. リソースのクリーンアップ
  • test 本体の_内部_で作成したリソースをクリーンアップするには、try-finally ブロックの代わりに addTearDown の使用を検討してください。

避ける例:

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

推奨例:

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. 設定(dart_test.yaml)

dart_test.yaml ファイルでテストランナーを設定します。一般的な設定には次のものがあります。

プラットフォーム

テストを実行する場所(vm、chrome、node)を指定します。

platforms:
  - vm
  - chrome
タグ

テストを分類して、特定のサブセットを実行します。

tags:
  integration:
    timeout: 2x

コードでの使用例:

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

タグの実行:dart test --tags integration

タイムアウト

テストのデフォルトのタイムアウトを設定します。

timeouts:
  2x # Double the default timeout
5. ファイル名
  • テストランナーに認識されるには、テストファイル名の末尾を _test.dart にする必要があります。
  • テストは test/ ディレクトリに配置します。
6. テスト設計、シーム、実際のテストダブル
  • テストのシームの使い分け(パッケージ統合テストと lib/src/ のユニットテスト):
    • パッケージレベルおよび統合テスト:package:<pkg>/<pkg>.dart (公開エントリーポイントのシーム)をインポートし、lib/<pkg>.dart のエクスポートは 公開利用者向けのものに厳密に限定します。
    • サブシステムのユニットテスト(lib/src/):エクスポートされていないパーサー、ステート マシン、データモデル、またはインターフェースがシンプルで内部の動作が豊富なアルゴリズムなど、 内部の深いモジュール(package:<pkg>/src/<subsystem>.dart)をインポートして、 エッジケースを直接ユニットテストします。呼び出し元が1つだけの薄いヘルパーは、それを所有する モジュールのエントリーポイントを通じてテストします。
  • 実際の実装とファーストパーティのフェイク(「失敗を検出できるテスト」):実際の依存関係と ファーストパーティのフェイクを使って、実運用の契約が破られたときにテストが失敗するようにします。 ファイルシステム I/O には package:test_descriptor(d.sandbox、d.dir、d.file)または Directory.systemTemp.createTempSync()(必ず addTearDown(() => tempDir.deleteSync(recursive: true)) に登録)を、サービスには インメモリデータベースまたはループバックの HttpServer インスタンスを、HTTP には package:http/testing.dart(MockClient)を、カスタムインターフェースには手書きのフェイクや スタブを使用し、DOM および JS/Wasm との相互運用には @TestOn('browser') を使用します。
  • 決定論的な非同期処理とマッチャーの診断(fakeAsync と package:checks):ユニットテストでは、実際の await Future.delayed(...) による待機を 避けてください(テストが不安定になり、テストスイートが遅くなります)。代わりに fakeAsync (package:fake_async)、制御可能な Completer、または注入したクロック/ランナーの コールバックを使用します。Stream の期待値は、エラーが伝播しない stream.listen(expectAsync1(...)) を未待機で使うのではなく、emitsInOrder / expectLater で検証します。また、expect(x == y, isTrue) や手動の try { ...; fail('...'); } catch (e) {} ブロックよりも、具体的なマッチャー (throwsA(isA<StateError>().having((e) => e.message, 'message', contains('...'))), completion(...)、unorderedEquals(...))を優先します。
  • 動作・構造・関係性のアサーション(変更検出テストは行わない):
    • 合成入力でコンシューマーの動作をテストする:定数、設定、モデルを_使用する_コードの観測可能な出力、状態遷移、境界条件を、合成ユニット入力で検証します(例:バリデーターに280文字と281文字を渡す、またはリポジトリ分類器に合成一時ディレクトリを渡す)。定数リテラルをそのまま繰り返すだけの同語反復的な変更検出テスト、静的な設定セット内の項目の所属を固定するテスト(publishedPackages.contains('foo'))、本番環境の特定のエンティティ名をハードコードするテスト(classifyRepo('specific-repo'))、あるいは単一の静的テンプレート定数内のアクション名、CLI フラグ、固定されたツールのバージョン/SHA を部分文字列で照合するテストは作成しないでください。設定セット、テンプレート定数、データセットの更新によって既存の変更検出アサーションが失敗した場合は、そのリテラルを一致するように更新するのではなく、変更検出アサーションを削除してください。
    • 実データとテンプレートの構造・関係性の不変条件を検証する:独立して変化するライブカタログ、JSON データセット、レジストリ、標準テンプレートをテストする場合は、件数(hasLength(33))、リテラルの設定項目、単一の定数テンプレート内の部分文字列をハードコードするのではなく、構造の妥当性とアーティファクト間の関係性に関する不変条件を検証してください(例:isNotEmpty、必須スキーマキーの存在、mergedCount + openCount == totalCount、またはワークフローテンプレートのジョブ ID とブランチ保護チェック名の一致)。件数や値の完全一致は、決定的なユニット入力に限ってください。
  • 直接実行・レンダリングによる検証:関数の呼び出し、CLI コマンドの実行、コンポーネントの直接レンダリングによって、実行時の動作、制御フロー、UI/CLI の出力を検証してください。ファイルテキストの直接読み取り(readAsStringSync())は、静的ドキュメントとのずれ(README.md の --help ブロック)、ビルド/パッケージメタデータの同期(BUILD、pubspec.yaml)、コードジェネレーターの入力/出力フィクスチャにのみ使用してください。

よく使うコマンド

  • dart test:すべてのテストを実行します。
  • dart test test/path/to/file_test.dart:特定のファイルのテストを実行します。
  • dart test --name "substring":説明に一致するテストを実行します。

関連スキル

dart-test-fundamentals は、テストの構成と設定に関する基本スキルです。テスト内でアサーションを書く場合は、次を参照してください。

  • dart-matcher-best-practices:従来の package:matcher(expect 呼び出し)を使用しているプロジェクトで活用してください。

コメント