JA Testing Testing Strategy - hiraishikentaro/rails-factorybot-jump GitHub Wiki

テスト: テスト戦略

テスト哲学

Rails FactoryBot Jump は、信頼性、保守性、現実的なテスト環境を重視する包括的なテスト戦略に従います。戦略は、分離されたコンポーネントのユニットテストと VSCode API インタラクションのインテグレーションテストのバランスを取ります。

テストフレームワークアーキテクチャ

コアテストスタック

プライマリフレームワーク: Mocha 10.8.2

  • 柔軟なテスト構成を持つ JavaScript テストフレームワーク
  • 非同期テストのサポート
  • 豊富なアサーションライブラリ統合
  • VSCode 操作用のカスタムタイムアウト処理

VSCode テスト環境: @vscode/test-electron 2.4.1

  • 実際の VSCode Extension Development Host でテストを実行
  • テスト中の完全な VSCode API アクセス
  • ファイルシステム統合を含む現実的なテスト環境
  • クロスプラットフォームテストサポート

モックフレームワーク: Sinon 17.0.1

  • 包括的なモックとスタブ機能
  • 分離されたユニットテスト用の VSCode API モック
  • ファイルシステム操作モック
  • 呼び出し検証と動作テスト

ソース: package.json#L78,L84,L88

テスト環境設定

テストランナーセットアップ (src/test/runTest.ts):

import { runTests } from "@vscode/test-electron";

async function main() {
  const extensionDevelopmentPath = path.resolve(__dirname, "../../");
  const extensionTestsPath = path.resolve(__dirname, "./suite/index");

  await runTests({
    extensionDevelopmentPath,
    extensionTestsPath,
  });
}

利点:

  • 実際の VSCode 環境でのテスト
  • 実際の拡張機能アクティベーションと非アクティベーション
  • 真のファイルシステム操作
  • 本物のユーザーインタラクションシミュレーション

ソース: src/test/runTest.ts

テストレベル

1. ユニットテスト

スコープ: 分離された個別のコンポーネントと関数

ターゲットコンポーネント:

  • ファクトリー検出正規表現パターン(src/utils/regexPatterns.ts
  • キャッシュ管理操作(src/services/cacheManager.ts
  • 設定解析ロジック(src/services/configurationManager.ts
  • リンク生成アルゴリズム
  • データモデル(src/models/factory.ts, location.ts, trait.ts
  • ファクトリーパーサー(src/services/factoryParser.ts

モック戦略:

// 例: VSCode ワークスペース API をモック
const mockWorkspace = {
  findFiles: sinon.stub(),
  getConfiguration: sinon.stub(),
  createFileSystemWatcher: sinon.stub(),
};

// 例: ファイルシステム操作をモック
const mockFs = {
  readFile: sinon.stub(),
  stat: sinon.stub(),
};

分離の利点:

  • 高速なテスト実行
  • 予測可能なテスト条件
  • 特定のロジックの簡単なデバッグ
  • 明確な失敗の帰属

2. インテグレーションテスト

スコープ: VSCode API とファイルシステムとのコンポーネントインタラクション

統合ポイント:

  • ドキュメントリンクプロバイダー登録
  • ファイルシステムウォッチャー機能
  • 設定変更処理
  • コマンド実行ワークフロー

実環境テスト:

// 例: 実際の VSCode ドキュメントでテスト
const document = await vscode.workspace.openTextDocument(testFileUri);
const provider = new FactoryLinkProvider();
const links = provider.provideDocumentLinks(document);

統合の利点:

  • 現実的な API 動作テスト
  • クロスコンポーネントインタラクション検証
  • エンドツーエンドワークフロー検証
  • プラットフォーム固有の動作テスト

3. システムテスト

スコープ: 現実的なシナリオでの完全な拡張機能

テストシナリオ:

  • 拡張機能アクティベーションと非アクティベーション
  • ファクトリーファイル検出と解析
  • リンク生成とナビゲーション
  • 設定更新とキャッシュ更新

ユーザーワークフローシミュレーション:

// 完全なユーザーワークフローをシミュレート
await activateExtension();
await openRubyTestFile();
await hoverOverFactoryCall();
await clickFactoryLink();
await verifyNavigationToFactory();

テストカテゴリ

1. コア機能テスト

ファクトリー検出テスト:

suite("ファクトリー検出", () => {
  test("基本的なファクトリー呼び出しを検出", () => {
    const text = "user = create(:user)";
    const matches = detectFactoryCalls(text);
    assert.strictEqual(matches.length, 1);
    assert.strictEqual(matches[0].factoryName, "user");
  });

  test("トレイト付きファクトリー呼び出しを検出", () => {
    const text = "admin = create(:user, :admin, :verified)";
    const matches = detectFactoryCalls(text);
    assert.strictEqual(matches[0].factoryName, "user");
    assert.deepStrictEqual(matches[0].traits, ["admin", "verified"]);
  });
});

キャッシュ管理テスト:

suite("キャッシュ管理", () => {
  test("ファイルからファクトリーキャッシュを構築", async () => {
    const provider = new FactoryLinkProvider();
    await provider.initializeFactoryFiles();
    const cache = provider.getFactoryCache();
    assert.ok(cache.has("user"));
    assert.ok(cache.has("post"));
  });

  test("ファイル変更時にキャッシュを更新", async () => {
    // キャッシュ無効化と再構築をテスト
  });
});

2. 設定テスト

設定処理テスト:

suite("設定", () => {
  test("デフォルトファクトリーパスを使用", () => {
    const config = getDefaultConfiguration();
    assert.deepStrictEqual(config.factoryPaths, ["spec/factories/**/*.rb"]);
  });

  test("カスタムファクトリーパスを尊重", async () => {
    await updateConfiguration({
      factoryPaths: ["test/factories/**/*.rb", "lib/factories/**/*.rb"],
    });
    const provider = new FactoryLinkProvider();
    const paths = provider.getFactoryPaths();
    assert.strictEqual(paths.length, 2);
  });
});

3. エッジケーステスト

エラーハンドリングテスト:

suite("エラーハンドリング", () => {
  test("ファクトリーファイル不足を適切に処理", async () => {
    // ファイルシステムが空の結果を返すようモック
    const provider = new FactoryLinkProvider();
    await provider.initializeFactoryFiles();
    // エラーを投げるべきではない
  });

  test("不正なファクトリーファイルを処理", async () => {
    // 無効な Ruby 構文でテスト
  });

  test("権限エラーを処理", async () => {
    // ファイルシステム権限エラーをモック
  });
});

パフォーマンステスト:

suite("パフォーマンス", () => {
  test("大量のファクトリーファイルを処理", async () => {
    // 100+ ファクトリーファイルでテスト
    const startTime = Date.now();
    await provider.initializeFactoryFiles();
    const duration = Date.now() - startTime;
    assert.ok(duration < 5000, "初期化は5秒以内に完了すべき");
  });

  test("大きなドキュメントのリンクを効率的に提供", () => {
    // 大きなテストファイルでテスト
  });
});

この包括的なテスト戦略により、拡張機能は、サポートされるすべてのプラットフォームとユースケースで高品質、信頼性、パフォーマンスを維持します。