テストネット運用の安全性向上と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で依存関係の脆弱性スキャンや定期的なアップデートテストを組み込むとよいでしょう。