StepCIで実APIをGitHub Actionsでテストしてみた
本記事は CyberAgent 26th Fresh Engineer's Advent Calendar 2025 の13日目の記事です。
- リポジトリ: https://github.com/huavcjj/stepci-playground
- テストツール: StepCI
- テスト対象: Connect RPC (gRPC 互換) の API
TL;DR
- StepCI を使って Connect RPC API のテストを CI で自動化
-
.http手動叩きでは「壊れても気づかない」課題を解決。StepCI で YAML ベースの API テストを実現 - JSONPath と JSON Schema でレスポンスの値と形を両面検証
- GitHub Actions で MySQL → マイグレーション → サーバー起動 → StepCI でテスト実行の流れを構築
.httpファイルでの開発(開発中は便利だった)
開発中は .http ファイルで API を叩いていました。GoLand では Cmd + Enter、VSCode では REST Client などの拡張機能で、リクエストを直接実行できます。開発中の動作確認には十分便利でした。
### CreateUser
POST http://localhost:8080/user.v1.UserService/CreateUser
Content-Type: application/json
{
"name": "test_user",
"email": "test_user@example.com"
}
IDE で直接実行できるので、開発フローに自然に組み込めます。レスポンスもその場で確認できて、手軽に API の動作を検証できました。
.http ファイルでの実行結果
一方、.http ファイルで手動実行した場合は、レスポンスの JSON がそのまま表示されるだけです。ステータスコードやレスポンスの形を目視で確認する必要があり、CI で自動化するのは難しいです。

どういう課題だったか
しかし、.http ファイルには以下の課題がありました:
- CI/CD で自動化できない: IDE での手動実行が前提で、CI に組み込めない
- アサーション機能が弱い: レスポンスの検証を目視で確認する必要がある
- 壊れても気づかない: 手動実行なので、誰も実行しなければ壊れても発見できない
- REST API しか対応していない: gRPC や GraphQL などのプロトコルには対応していない
- ストリーミングに対応していない: Server-Sent Events (SSE) や WebSocket などのストリーミングレスポンスを検証できない
Note: Connect RPC は HTTP/JSON で叩けるため、
.httpファイルでも開発中は便利でした。しかし、CI で自動化するには別のツールが必要でした。
単体テストのモックは実装ズレに鈍感で、実 API を叩ける CI の「見張り役」が欲しいという課題がありました。この課題を解決するため、CI/CD で使える API テストツールを比較検討し、StepCI を採用することにしました。
ツール比較で見たポイント
CI/CD で使える API テストツールとして、.http、hurl、stepci を比較しました。以下の4点を重視しました:
- Docker/CLI でそのまま CI に積めること
- ワークフロー(依存するリクエストの連鎖)を書けること
- アサーションが表現力豊か(JSONPath など)であること
- gRPC/HTTP の両面で Connect RPC を叩けること
| 項目 | .http | hurl | StepCI |
|---|---|---|---|
| CI/CD 対応 | ❌ IDE での手動実行が前提 | ✅ CLI で実行可能 | ✅ CLI/Docker で実行可能 |
| ワークフロー | ❌ 単一リクエストのみ | ⚠️ 限定的(変数は使えるが連鎖は弱い) | ✅ captures で値を受け渡し可能 |
| アサーション | ❌ 目視確認のみ | ✅ JSONPath 対応 | ✅ JSONPath + JSON Schema |
| プロトコル対応 | ⚠️ REST API のみ | ⚠️ REST API のみ | ✅ REST / GraphQL / gRPC / WebSocket |
| 学習コスト | ✅ 低い(シンプルな記法) | ✅ 低い(.http に近い記法) | ✅ 低い(YAML で直感的) |
| ストリーミング | ❌ 非対応 | ❌ 非対応 | ⚠️ リクエスト・レスポンス型前提 |
この4点を小コストで満たし、YAML で読みやすかったのが StepCI でした。
StepCI ざっくり紹介
- 目的: 「実 API を CI で毎回叩いて検証する」を前提に設計された API テストランナー
- 形式: YAML でテストを書く。
version/name/env/testsを持ち、設定ファイルのように扱える - プロトコル:
http / gql / grpc / wsをサポート(公式の Protocols セクション準拠) - 検証:
checkでstatus・jsonpath・schema(JSON Schema)を組み合わせ、値と形を両面で検証 - データ受け渡し:
capturesでレスポンスから値を抜き、${{captures.xxx}}として次ステップで再利用 - 実行形態: CLI と Docker イメージを公式が提供。Docker なら
-v $(pwd)/tests:/testsでマウントしstepci/stepci run /tests/foo.yml - ログ: 失敗時にどのステップが落ちたかをテーブル形式で出力し、GitHub Actions でも追いやすい
サンプル tests/greet-service.yml
version: "1.1"
name: Greet Service Tests
env:
host: http://localhost:8080
tests:
greet_service:
steps:
- name: Greet
http:
url: ${{env.host}}/greet.v1.GreetService/Greet
method: POST
headers:
Content-Type: application/json
json:
name: test
check:
status: 200
schema:
type: object
properties:
message:
type: string
required:
- message
-
envでエンドポイントをまとめ、tests配下でステップを列挙する公式推奨の構造 -
check.statusで HTTP ステータス、check.schemaでレスポンス形を同時に担保 - もっと複雑な API は
check.jsonpathやcapturesを追加していく(後述のレシピ参照)
5 分ハンズオン
公式の「Run via CLI/Docker」手順に合わせ、手元のリポジトリ構成に載せて動かします。
前提条件
- Docker / Docker Compose が動く環境
- Node/NPM があり
npm install -g stepciできる(Docker でも可)
セットアップ手順
1. リポジトリをクローン
git clone https://github.com/huavcjj/stepci-playground.git
cd stepci-playground
2. サービスを起動
make docker-up # docker-compose で MySQL と Web サーバーを起動
3. 依存関係のインストールとコード生成
make setup-ci # go mod / buf / protoc / sqlc / migrate up まで
4. StepCI テストを実行
# 1 ファイルずつ実行
stepci run tests/user-service.yml
# 全テストファイルをまとめて実行
make test
Note:
make testは StepCI が無ければ npm でインストールし、tests/*.ymlを順番に実行するだけのシンプル構成です。
実行結果の比較
StepCI での実行結果
StepCI を実行すると、各ステップの実行結果がテーブル形式で表示されます。成功したステップは緑色、失敗したステップは赤色で表示され、どの API が問題なのかが一目で分かります。

StepCI の利点: テストファイルに書いた check の条件を自動で検証し、失敗時にはどのステップのどの検証が失敗したかを明確に示してくれます。
コードから読む StepCI レシピ
1. シンプルな API テスト(Greet Service)
- name: Greet
http:
url: ${{env.host}}/greet.v1.GreetService/Greet
method: POST
headers:
Content-Type: application/json
json:
name: test
check:
status: 200
jsonpath:
$.message:
- eq: "Hello, test!"
schema:
type: object
properties:
message:
type: string
required:
- message
リクエストを送って、ステータスコードとレスポンスの形を検証するだけのシンプルなパターン。サーバー起動やルーティングの初期不具合を拾いやすい。
2. JSONPath で値を検証する
- name: CreateUser
http:
url: ${{env.host}}/user.v1.UserService/CreateUser
method: POST
headers:
Content-Type: application/json
json:
name: "test_user"
email: "test_user@example.com"
check:
status: 200
jsonpath:
$.user.name:
- eq: "test_user"
$.user.email:
- eq: "test_user@example.com"
schema:
type: object
properties:
user:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
required:
- id
- name
- email
required:
- user
captures:
user_id:
jsonpath: $.user.id
check.jsonpath でレスポンスの特定フィールドの値を検証できる。captures で値を拾って、後続のステップで ${{captures.user_id}} として使える。
3. JSON Schema でレスポンスの形を保証する
check:
status: 200
jsonpath:
$.users[0].id:
- eq: ${{captures.user_id}}
$.users[0].name:
- eq: "test_user_updated"
$.users[0].email:
- eq: "test_user_updated@example.com"
schema:
type: object
properties:
users:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
required:
- users
check.schema は公式ドキュメントの Validation セクションで推奨されている書き方。JSONPath で「値」、Schema で「形」を担保する二段構えにしておくと、後続でフィールド追加・削除をしたときに落ちやすい。
4. 複数ステップでワークフローを書く
- name: GetUser
http:
url: ${{env.host}}/user.v1.UserService/GetUser
method: POST
headers:
Content-Type: application/json
json:
id: ${{captures.user_id}}
check:
status: 200
jsonpath:
$.user.id:
- eq: ${{captures.user_id}}
$.user.name:
- eq: "test_user"
$.user.email:
- eq: "test_user@example.com"
schema:
type: object
properties:
user:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
createdAt:
type: string
updatedAt:
type: string
required:
- id
- name
- email
required:
- user
前のステップで captures した値を次のステップで使うことで、複数の API を連鎖させたテストが書ける。
GitHub Actions で StepCI をどう回しているか
.github/workflows/api-test.yml で StepCI を実行するための準備と実行を直列に並べただけ:
-
MySQL サービスを起動:
servicesで MySQL 8.0 コンテナを起動。ヘルスチェックで起動完了を待つ -
コード生成 & マイグレーション:
make install-toolsで buf、sqlc、migrate などをインストール →make generateで protobuf と SQL からコード生成 →make migrate-upでデータベーススキーマを適用 -
API サーバーを起動して待機:
make buildでサーバーをビルド → バックグラウンドで起動(./server &)→curlで/greet.v1.GreetService/Greetにリクエストして起動完了を確認(最大60秒待機) -
StepCI でテスト実行:
make testで StepCI が未インストールなら自動インストール →tests/配下の YAML ファイルを StepCI で順番に実行
Makefile の test ターゲットに「StepCI で YAML を全部回すだけ」を寄せておくと、ローカルと CI の入口を揃えられる。ログは StepCI がテーブルで出してくれるので追いやすい。
実行結果:

StepCI の実行方法
ローカルでは make test を実行すると、StepCI が未インストールなら自動でインストールされ、tests/ 配下の YAML ファイルを順番に実行する:
make test
# StepCI が未インストールなら自動インストール
# tests/*.yml を順番に実行
CI でも同じ make test を実行するため、ローカルと CI で同じテストが実行される。
StepCI の検証機能
StepCI では check セクションで以下の検証が可能:
-
ステータスコード:
status: 200で HTTP ステータスコードを検証 -
JSONPath:
jsonpathでレスポンスの特定の値を検証(eq、ne、existsなど) -
JSON Schema:
schemaでレスポンスの構造と型を検証
check:
status: 200
jsonpath:
$.user.id:
- eq: ${{captures.user_id}}
$.user.name:
- eq: "test_user"
schema:
type: object
properties:
user:
type: object
properties:
id: { type: string }
name: { type: string }
これにより、レスポンスの値と構造の両方を検証でき、API の変更を確実に検出できる。
使ってみて感じたハマりどころ
- ストリーミング系(SSE / WebSocket)は不得意: リクエスト・レスポンス型前提
-
依存関係がある API のテストでは事前準備が必要:
Setup_ステップが必要で YAML が伸びる - クラウド依存の API は実サービスが必要: 実サービスを立てないと検証できず、結局モックと併用になる場面がある
- マイクロサービス全部乗せの統合テストは重い: 単一サービスの健全性チェックに割り切ると楽
まとめと所感
- 「実 API を CI で毎回叩く」用途なら StepCI は手軽で十分強い
- YAML で書くのでレビューしやすく、Connect RPC も HTTP モードで素直に叩けた
- JSONPath と Schema の二段構えで、レスポンスの値と形の両方を検証できるのが安心
- ストリーミングや大規模統合は別ツールを併用するのが現実的
- ローカルは
.httpで素振り、CI は StepCI で自動検証、の二刀流が心地よかった
参考リンク
Discussion