テストネット運用の安全性向上とPDCA高速化を狙い、MMBotのCIパイプラインにE2Eテストを組み込みました。今回はWebSocket/HTTP呼び出しを完全モック化し、「o4-mini」AI伴走開発を最大活用して、1分以内に全チェックが完走する環境を実現した流れをまとめます。
今回のゴール
- CI上でE2Eを自動実行:Pull Request→Merge時に必ずE2Eが走るように
- WebSocket&HTTP完全モック化:実API依存を排除し、安定・高速なテストを実現
- ChatGPT(o4-mini)伴走:プロンプトドリブンで差分リファクタ&ワークフロー構築
技術スタックと前提
- 言語・依存管理:Python 3.11 + Poetry
- コンテナ管理:Docker Compose V2
- CI/CD:GitHub Actions
- 外部連携:Bybit Testnet API/Slack Webhook
- AI伴走:ChatGPT o4-mini をモデル切り替えで活用
1. やったこと
| カテゴリ | 作業内容 | 効果 | 
|---|---|---|
| CI整備 | .github/workflows/e2e.ymlに E2E ジョブ追加 | PR/Merge 時に自動で E2E が実行される | 
| モック化 | 環境変数 MOCK_STREAMで WS & HTTP をモック | 実 API 非依存で安定&高速テスト | 
| スクリプト | tests/e2e/testnet_checks.shを A–H フェーズ対応にリファクタ | 手動確認フェーズを自動スキップ&フェーズ検証 | 
| Bot実装 | run_loop()にモック判定を追加し、ClientSessionを動的生成 | モック/実運用を同一コードベースで兼用 | 
2. コード抜粋
# src/mmbot/cli.py(抜粋)
MOCK_STREAM = os.getenv("MOCK_STREAM", "").lower() in ("1", "true", "yes")
async def run_loop(...):
    if MOCK_STREAM:
        logger.debug("MOCK_STREAM enabled: skipping real WebSocket connect")
        orderbook = {"bid": 100.0, "ask": 100.0}
        sess = aiohttp.ClientSession()
    else:
        async with pybotters.Client(base_url=ws_public) as ws, \
                   aiohttp.ClientSession() as sess:
            await ws.ws_connect(...)
            ...
# .github/workflows/e2e.yml(抜粋)
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker images
        run: docker compose build mmbot
      - name: Run E2E tests
        env:
          MOCK_STREAM: '1'                     # WS/HTTPをモック
          SLACK_ENABLE: 'true'
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_WEBHOOK_URL }}
        run: |
          chmod +x tests/e2e/testnet_checks.sh
          printf "\n" | ./tests/e2e/testnet_checks.sh
3. 結果と効果
- 実行時間:1分以内に A–H 全 8 フェーズが完了(旧来5分→1分)
- 安定性:テストネット本番相当のモックにより外部不安定要因を排除
- 開発速度:AI伴走でスクリプト+CI設定を約30%短時間実装
4. 学び・改善ポイント
- ClientSession のクローズ忘れ:短命実行向けでも明示的に await sess.close()を入れるとさらにクリーン
- ユニットテスト強化:MOCK_STREAMモードの振る舞いを pytest でカバーすると回帰防止に有効
- ドキュメント追加:環境変数やモックフラグの説明を README に追記
5. 次の予定
- 実API接続版E2E の整備(Testnet Live チャネルで 24h 運転)
- Prometheus+Grafana で PnL/DD を可視化
- FastAPI+WebSocket ダッシュボードβ 公開
- Adaptive Spread Entry/Funding Rate 管理 の v0.2 機能開発
付録:E2Eチェックフェーズ一覧
| フェーズ | 内容 | 
|---|---|
| A | 手動確認(残高・サブアカウント制限) | 
| B | DD guard(損失0.01%で停止) | 
| C | spread-skip(閾値以下は発注抑制) | 
| D | API error(Exception でも継続) | 
| E | Slack 404(通知失敗でも継続) | 
| F | max_cycles=3(3周で正常終了) | 
| H | DD auto-flat(大幅DD時に完全決済) | 
今回の合言葉:
「モックで地盤を固め、CIで網を張り、次は空中戦へ」💪
以上が、CI×E2Eモック化による高速安全チェックの流れでした。次回もお楽しみに!
おまけ:懸念点・抜け漏れチェック
- ClientSessionのクローズ漏れ- モック時は明示的に aiohttp.ClientSession()を作っているものの、await sess.close()を呼ばないとリソースリークにつながる可能性があります。
- 本番モードでも例外パスでのセッションクローズが抜けるケースがないか要確認。
 
- モック時は明示的に 
- WebSocket モックの挙動簡素化
- モック時は板情報を固定値(bid=ask=100)でセットしていますが、実際の「板の変動」を再現していないため、スキップ/エントリー判断ロジックに偏りが出るかも。
- モック用に簡易的な価格変動パターンを作っておくとより網羅的なテストになるでしょう。
 
- Slack 通知のモック限界
- CIでは通知失敗を WARNログで扱い続行していますが、実環境で頻発するとロストアラートの見落としリスクがあります。
- 「通知待ち」「再試行ロジック」「エスカレーション手順」も別途ユニットテストしておくと安心です。
 
- CIでは通知失敗を 
- 環境変数/ファイル参照の散在
- .env.testnetや- MOCK_STREAMフラグを複数箇所で扱うため、新規環境構築時に設定漏れが起こりやすい状態。
- 設定仕様を一箇所にまとめたドキュメント化や、起動チェックで必須項目を明示的にバリデートする仕組みがあるとミスを防げます。
 
- ユニットテストとの重複カバレッジ
- E2Eで一連のフローを動かすテストはあるものの、個々の純関数(should_enter/dd_warnなど)との組み合わせで“境界値”が抜けている可能性あり。
- E2Eフェーズでは網羅できない細かいエラーケースをユニットテストで補完すると、品質がさらに向上します。
 
- E2Eで一連のフローを動かすテストはあるものの、個々の純関数(
- CI 実行環境とローカル環境のギャップ
- ローカルでは Docker for Mac を使い、CIでは Linux 上の Docker Compose V2。環境差異で微妙に動作が変わるケースも。
- たとえばファイルパスの大文字・小文字、sed -iの挙動など、CI用に一度“真っ新”のクローンで動作確認しておくと安心です。
 
- 依存ライブラリのバージョン固定
- pybottersや- aiohttpのメジャーアップデートで API 仕様が変わるリスクがあります。
- Poetry の pyproject.tomlで「~=」指定にとどめず、CIで依存関係の脆弱性スキャンや定期的なアップデートテストを組み込むとよいでしょう。
 
