← ブログ一覧に戻る
業務自動化

Cursor/Claude CodeでRPAのテストコードを自動生成する実践例(Playwright)

#Cursor#Claude Code#Playwright#テスト自動化#RPA#コーディングエージェント

はじめに

RPAを開発した後、その動作を検証するテストコードを書くのは時間がかかります。特に、正常系・異常系のテストケース、エッジケースのテスト、モックを使ったテストなど、様々なパターンを実装する必要があります。

CursorClaude Codeなどのコーディングエージェントを活用することで、RPAのテストコードを効率的に自動生成できます。この記事では、実際のプロジェクトで活用した経験を基に、テストコードの自動生成方法を解説します。

RPAテストコードの重要性

1. 動作検証の自動化

RPAの動作を手動で確認するのは時間がかかり、見落としも発生しがちです。テストコードを書くことで、自動的に動作を検証できます。

2. リグレッション防止

RPAのコードを変更した際、既存の機能が壊れていないかを確認するためにテストコードが重要です。

3. ドキュメントとしての役割

テストコードは、RPAの期待される動作を明確に示すドキュメントとしても機能します。

実践例1:基本的なテストコードの生成

プロンプト設計

効果的なプロンプトの例:

PlaywrightでRPAのテストコードを作成してください。

対象RPA:
- ログイン処理: login(page, email, password)
- CSVダウンロード処理: downloadSalesReport(page)

テスト要件:
- 正常系: ログイン成功、CSVダウンロード成功
- 異常系: 不正な認証情報、要素が見つからない
- エッジケース: タイムアウト、ネットワークエラー

使用ライブラリ: @playwright/test
テストフレームワーク: Jest風の記述

生成されたテストコード例

import { test, expect } from '@playwright/test';
import { login, downloadSalesReport } from '../src/rpa';

test.describe('RPA Tests', () => {
  test.beforeEach(async ({ page }) => {
    // 各テスト前にベースURLに移動
    await page.goto('https://example.com/admin');
  });

  test.describe('ログイン処理', () => {
    test('正常系: 正しい認証情報でログイン成功', async ({ page }) => {
      await login(page, '[email protected]', 'correctpassword');
      
      // ダッシュボードが表示されることを確認
      await expect(page.getByTestId('dashboard')).toBeVisible();
      await expect(page).toHaveURL(/.*dashboard/);
    });

    test('異常系: 不正なメールアドレスでログイン失敗', async ({ page }) => {
      await expect(async () => {
        await login(page, '[email protected]', 'password123');
      }).rejects.toThrow();
      
      // エラーメッセージが表示されることを確認
      await expect(page.getByText('ログインに失敗しました')).toBeVisible();
    });

    test('異常系: 不正なパスワードでログイン失敗', async ({ page }) => {
      await expect(async () => {
        await login(page, '[email protected]', 'wrongpassword');
      }).rejects.toThrow();
      
      await expect(page.getByText('パスワードが正しくありません')).toBeVisible();
    });

    test('異常系: 空の認証情報でログイン失敗', async ({ page }) => {
      await expect(async () => {
        await login(page, '', '');
      }).rejects.toThrow();
    });
  });

  test.describe('CSVダウンロード処理', () => {
    test('正常系: CSVダウンロード成功', async ({ page, context }) => {
      // ログイン
      await login(page, '[email protected]', 'correctpassword');
      
      // ダウンロードを監視
      const [download] = await Promise.all([
        page.waitForEvent('download'),
        downloadSalesReport(page),
      ]);
      
      // ファイルがダウンロードされたことを確認
      expect(download.suggestedFilename()).toContain('.csv');
      const path = await download.path();
      expect(path).toBeTruthy();
      
      // ファイルの内容を確認(オプション)
      const fs = require('fs');
      const content = fs.readFileSync(path, 'utf-8');
      expect(content).toContain('売上');
    });

    test('異常系: ログインせずにダウンロード試行', async ({ page }) => {
      await expect(async () => {
        await downloadSalesReport(page);
      }).rejects.toThrow();
    });

    test('異常系: 要素が見つからない', async ({ page }) => {
      await login(page, '[email protected]', 'correctpassword');
      
      // 存在しないボタンをクリックしようとする
      await expect(async () => {
        await page.getByRole('button', { name: '存在しないボタン' }).click({ timeout: 1000 });
      }).rejects.toThrow();
    });
  });
});

実践例2:統合テストの生成

複数の処理を組み合わせた統合テストを生成する例です。

エージェントへの指示

このRPAの統合テストを作成してください。

RPAフロー:
1. ログイン
2. ダッシュボード確認
3. 売上レポートページに移動
4. CSVダウンロード
5. ダウンロードしたCSVの内容を検証

テスト要件:
- エンドツーエンドの動作確認
- 各ステップで適切な待機処理
- エラー時のスクリーンショット保存
- テストデータのクリーンアップ

生成されたコード例

import { test, expect } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';

test.describe('RPA統合テスト', () => {
  const downloadDir = path.join(__dirname, '../downloads');
  
  test.beforeAll(() => {
    // ダウンロードディレクトリを作成
    if (!fs.existsSync(downloadDir)) {
      fs.mkdirSync(downloadDir, { recursive: true });
    }
  });

  test.afterEach(async ({ page }) => {
    // テスト失敗時にスクリーンショットを保存
    if (test.info().status === 'failed') {
      const screenshotPath = path.join(
        downloadDir,
        `failed-${test.info().title.replace(/\s/g, '-')}-${Date.now()}.png`
      );
      await page.screenshot({ path: screenshotPath, fullPage: true });
      console.log(`スクリーンショット保存: ${screenshotPath}`);
    }
  });

  test('エンドツーエンド: ログインからCSVダウンロードまで', async ({ page, context }) => {
    // 1. ログイン
    await login(page, process.env.TEST_EMAIL!, process.env.TEST_PASSWORD!);
    
    // 2. ダッシュボードが表示されることを確認
    await expect(page.getByTestId('dashboard')).toBeVisible({ timeout: 10000 });
    await expect(page).toHaveURL(/.*dashboard/);
    
    // 3. 売上レポートページに移動
    await page.getByRole('link', { name: '売上レポート' }).click();
    await expect(page).toHaveURL(/.*sales-report/);
    await expect(page.getByRole('heading', { name: '売上レポート' })).toBeVisible();
    
    // 4. CSVダウンロード
    const [download] = await Promise.all([
      page.waitForEvent('download'),
      page.getByRole('button', { name: 'CSVダウンロード' }).click(),
    ]);
    
    // 5. ダウンロードしたCSVの内容を検証
    const downloadPath = await download.path();
    expect(downloadPath).toBeTruthy();
    
    const csvContent = fs.readFileSync(downloadPath!, 'utf-8');
    expect(csvContent).toContain('売上');
    expect(csvContent.split('\n').length).toBeGreaterThan(1); // ヘッダー + データ行
    
    // CSVの構造を検証
    const lines = csvContent.split('\n');
    const header = lines[0].split(',');
    expect(header).toContain('日付');
    expect(header).toContain('売上金額');
  });
});

実践例3:モックを使ったテスト

外部APIやデータベースに依存しないテストを生成する例です。

エージェントへの指示

このRPAのモックを使ったテストを作成してください。

要件:
- 外部APIの呼び出しをモック
- データベースアクセスをモック
- ファイルシステム操作をモック
- 各モックで正常系・異常系をテスト

使用ライブラリ: @playwright/test, MSW (Mock Service Worker)

生成されたコード例

import { test, expect } from '@playwright/test';
import { rest } from 'msw';
import { setupServer } from 'msw/node';

// モックサーバーの設定
const server = setupServer(
  // 正常系: API成功
  rest.get('https://api.example.com/sales', (req, res, ctx) => {
    return res(
      ctx.status(200),
      ctx.json({
        sales: [
          { date: '2026-01-01', amount: 100000 },
          { date: '2026-01-02', amount: 150000 },
        ],
      })
    );
  }),
  
  // 異常系: APIエラー
  rest.get('https://api.example.com/sales-error', (req, res, ctx) => {
    return res(ctx.status(500), ctx.json({ error: 'Internal Server Error' }));
  })
);

test.beforeAll(() => server.listen());
test.afterEach(() => server.resetHandlers());
test.afterAll(() => server.close());

test.describe('モックを使ったRPAテスト', () => {
  test('正常系: API成功時の処理', async ({ page }) => {
    await page.goto('https://example.com/admin');
    await login(page, '[email protected]', 'password');
    
    // APIが正常に呼び出されることを確認
    const response = await page.waitForResponse('https://api.example.com/sales');
    expect(response.status()).toBe(200);
    
    const data = await response.json();
    expect(data.sales).toHaveLength(2);
  });

  test('異常系: APIエラー時の処理', async ({ page }) => {
    await page.goto('https://example.com/admin');
    await login(page, '[email protected]', 'password');
    
    // エラーページに移動
    await page.goto('https://example.com/admin/sales-error');
    
    // エラーメッセージが表示されることを確認
    await expect(page.getByText('データの取得に失敗しました')).toBeVisible();
  });
});

実践例4:パフォーマンステストの生成

RPAの実行時間やリソース使用量を測定するテストを生成する例です。

エージェントへの指示

このRPAのパフォーマンステストを作成してください。

要件:
- 実行時間の測定
- メモリ使用量の監視
- ネットワークリクエスト数のカウント
- パフォーマンス基準値との比較
- スローダウンの検出

生成されたコード例

import { test, expect } from '@playwright/test';

test.describe('RPAパフォーマンステスト', () => {
  test('ログイン処理の実行時間', async ({ page }) => {
    const startTime = Date.now();
    
    await page.goto('https://example.com/admin');
    await login(page, '[email protected]', 'password');
    
    const endTime = Date.now();
    const executionTime = endTime - startTime;
    
    // 実行時間が5秒以内であることを確認
    expect(executionTime).toBeLessThan(5000);
    console.log(`ログイン処理時間: ${executionTime}ms`);
  });

  test('CSVダウンロード処理の実行時間', async ({ page }) => {
    await login(page, '[email protected]', 'password');
    
    const startTime = Date.now();
    await downloadSalesReport(page);
    const endTime = Date.now();
    
    const executionTime = endTime - startTime;
    expect(executionTime).toBeLessThan(10000); // 10秒以内
    console.log(`CSVダウンロード処理時間: ${executionTime}ms`);
  });

  test('ネットワークリクエスト数の監視', async ({ page }) => {
    const requests: string[] = [];
    
    page.on('request', (request) => {
      requests.push(request.url());
    });
    
    await page.goto('https://example.com/admin');
    await login(page, '[email protected]', 'password');
    await downloadSalesReport(page);
    
    // リクエスト数が適切な範囲内であることを確認
    expect(requests.length).toBeLessThan(50);
    console.log(`総リクエスト数: ${requests.length}`);
  });

  test('メモリ使用量の監視', async ({ page, context }) => {
    const client = await context.newCDPSession(page);
    
    await login(page, '[email protected]', 'password');
    
    // メモリ使用量を取得
    const memoryInfo = await client.send('Runtime.getHeapUsage');
    const usedMemoryMB = memoryInfo.usedSize / 1024 / 1024;
    
    // メモリ使用量が100MB以内であることを確認
    expect(usedMemoryMB).toBeLessThan(100);
    console.log(`メモリ使用量: ${usedMemoryMB.toFixed(2)}MB`);
  });
});

コーディングエージェント活用のベストプラクティス

1. テストケースの網羅性

エージェントに以下の観点でテストケースを生成してもらいます。

  • 正常系: 期待通りの動作
  • 異常系: エラーケース
  • エッジケース: 境界値や特殊な状況
  • 統合テスト: 複数処理の組み合わせ

2. テストデータの管理

テストデータを適切に管理するコードも生成してもらいます。

// テストデータの管理
const testData = {
  validCredentials: {
    email: '[email protected]',
    password: 'password123',
  },
  invalidCredentials: {
    email: '[email protected]',
    password: 'wrongpassword',
  },
};

3. テストの保守性

テストコードが保守しやすいように、以下の点を意識します。

  • DRY原則: 重複を避ける
  • 可読性: テストの意図が明確
  • 独立性: テスト同士が依存しない

注意点と制限事項

テストコードの限界

  • UI変更への対応: UIが変わるとテストが失敗する可能性がある
  • 実行環境: テスト環境と本番環境の違いに注意
  • フレーキーテスト: タイミングによって失敗する可能性

エージェントの限界

  • 最新のAPI: Playwrightの最新機能を理解していない場合がある
  • テスト設計: テストの設計思想は人間が判断する必要がある

まとめ

CursorやClaude Codeなどのコーディングエージェントを活用することで、RPAのテストコードを効率的に自動生成できます。

効果的な活用方法:

  • 具体的で構造化されたプロンプトを使用
  • 正常系・異常系・エッジケースを網羅
  • モックを使った独立したテスト
  • パフォーマンステストも自動生成

改善前:

  • テストコードの作成に数時間かかる
  • テストケースの網羅性が不十分
  • テストの保守性が低い

改善後:

  • エージェントの支援でテストコードを迅速に生成
  • 網羅的なテストケースが自動生成
  • 保守性の高いテストコードが実現

コーディングエージェントは、RPAテスト開発の「強力なパートナー」として活用することで、より効率的で信頼性の高いテストを実現できます。


関連リンク: