🪜

StepCIを使ってSaaSのAPIを利用するAPIサーバーのE2Eテストやってみた

に公開

はじめに

こんにちは、ソフトウェアエンジニアリングチームの山川です。
2025年4月にウェルスナビへ新卒入社し、主にID認証基盤(以降、ID基盤)チームで「ウェルスナビID」の運用や新規機能の開発に従事しています。
https://note.com/wealthnavi_hr/n/n323875e0c7a0

この記事では、SaaSが提供するAPI(以降「SaaS API」)を呼び出す必要がある内部APIに対して、CI上で安全に実行できるE2EテストをStepCIで実装した事例を紹介します。

対象読者

  • CIでAPIテストの品質向上に関心のある方
  • OpenAPIを使っている、あるいはAPIのE2Eテストを自動化したい方
  • SaaS APIを利用するシステムのテスト設計に悩んでいる方

得られること

  • StepCIを使ってSaaS APIを含むE2Eテストをする方法
  • トークンやテストデータの受け渡し、OpenAPIを使ったテスト生成
  • CIでの実行時に気をつけるポイント(レート制限・クリーンアップなど)

背景と目的

弊社のID基盤チームではSaaSを利用しており、認証およびユーザ情報を管理しています。
ID基盤のAPIではドキュメンテーションにOpenAPIを採用しています。
OpenAPIによりAPI仕様が明確であることから統合テストを自動で行いたいと考えていました。

上司と実際にどのようなテストを実施したいか話し合い、具体的なニーズは以下になりました。

  • SaaS APIを使用した弊社サービスの機能が想定どおりのデータを作成・更新していることを確認したい
  • SaaSが保持するデータの状態もテストに含めたい
  • テストはCIで自動実行できるようにしたい

SaaS APIを使用する上で制約もいくつかあります。
もちろんですが利用しているSaaSのDBには直接アクセスできませんし、SaaS APIはレート制限があるためやみくもに繰り返し実行すると失敗する可能性があります。
またSaaS側でもテスト実行ごとに一意なデータを作成しテスト終了後にクリーンアップする必要があります。

StepCIを選んだ理由

上記の目的を実現できるAPIのモックテストツールとしてStepCIを用いたシナリオテストを採用しました。
StepCI[1]とは、APIテストをステップで記述・実行できるツールです。

  • テスト前後でテストデータの設定やクリーンアップができる機能[2]がある
  • テンプレートエンジン[3]があり、URLに特殊文字を含むパスパラメータの扱いが楽
  • OpenAPIのインポート機能があり、API定義に基づいてテストを自動生成できる
  • delayの設定がありレート制限に配慮した実行ができる

https://stepci.com/

実施方針

  1. OpenAPIから共通ステップやモック用のスキーマを生成する
  2. テストの前後でトークン取得やテストデータの準備・削除といった処理を実装する
  3. StepCIでシナリオテストを作成する
  4. CI上で立ち上げたアプリケーションをStepCIでE2Eテストする

具体例

ここでは簡単なサンプルを示します。

ポイント:

  • setupでSaaS APIの管理トークンを取得(管理APIへのアクセスに使う)
  • 内部APIに対して、テストデータを用いてテストを実行
  • 最後にSaaS APIのテストデータを削除
stepci-sample.yaml
version: "1.1"
name: API Tests
env:
  test: localhost:9091
  domain: example.com

before:
  name: "Set up user"
  steps:
    - name: "テストユーザー作成"
      http:
        url: https://${{ env.domain }}/api/users
        method: POST
        auth:
          bearer:
            token: ${{ secrets.token }}
        body: |
          {
            "email": "stepci.test1@example.com",
            "name": "StepCI Test User1",
            "password": "!pass123"
          }
        check:
          status: 201
          schema:
            type: object
            properties:
              user_id:
                type: string
            required:
              - user_id
        captures:
          user_id:
            jsonpath: $.user_id

tests:
  emailUpdateTest:
    name: メール変更確認テスト
    steps:
      - id: updateMail
        name: メールアドレスの変更
        http:
          url: https://${{ env.test }}/email
          method: PUT
          headers:
            Content-Type: application/json
            accept: application/json
          json:
            providerId: ${{ captures.user_id }}
            email: "stepci.update@example.com"
            emailVerified: true
          check:
            status: 200

      - delay: 1s
      
      - id: getUser
        name: ユーザープロファイル取得
        http:
          url: https://${{env.test}}/user/${{ captures.user_id | url_encode }}
          method: GET
          check:
            status: 200
            schema:
              $ref: "#/components/schemas/UserResponse"
            jsonpath:
              $.email:
                - isString: true
                - eq: "stepci.update@example.com"

after:
  name: "Clean up User"
  steps:
    - name: "Delete User"
      http:
        url: "https://${{ env.domain }}/api/users/${{ captures.user_id | url_encode }}"
        method: DELETE
        headers:
          content-type: application/json
        auth:
          bearer:
            token: ${{ secrets.token }}
        check:
          status: 204

components:
  schemas:
    UserResponse:
      type: object
      properties:
        userId:
          type: string
          description: ユーザID
        email:
          type: string
          description: メールアドレス
        name:
          type: string
          description: ユーザ名

テストデータ

StepCIはテスト間でデータを共有することができます。
例に挙げたサンプルでは、テストの前(beforeのセクション)に作成したユーザのIDをuser_idとしてキャプチャ[4]しました。
この値を${{ captures.user_id }}として後続のテストセクションで使うことができます。

またテンプレートエンジン[3:1]がありURLエンコードなどの値の加工ができるため、特に問題なくAPIのエンドポイントにアクセスできました。

# 環境変数やsetupで取得した値を使い回してテストが可能
      url: https://${{ env.test }}/user/${{ captures.user_id | url_encode }}

OpenAPIからの自動生成

StepCIのCLIの機能ではOpenAPI仕様を読み込んでリクエスト定義やスキーマを自動生成できます[5]
今回はシナリオテストなので生成したテストをそのまま使用しませんでしたが、手作業で一から書く必要がなく簡単に導入できました。

結果と展望

実施して得られた効果

今回の取り組みを通じてSaaS APIを含めたフロー全体をシナリオとして自動で検証できるようになり、変更による副作用や想定外の振る舞いを早期に検出できるようになりました。
OpenAPIを活用することでリクエスト定義やスキーマなどテストの共通部分を共通化・自動生成でき、手作業を減らすことができると経験できました。
またSaaS APIのレート制限による実行頻度の調整を考えることも必要だと学びました。

展望

一方で今後テストでやりたいことはまだ残っています。
例えば、SaaS APIに接続できないといったネットワーク起因によるテストの不安定さを考えたリトライ設定や、シナリオの拡充などが挙げられます。
またAPIのレスポンスの検証部分では正規表現で検証しています。新規で追加されるパラメータは検知できないので、OpenAPIがアップデートされたら自動でスキーマも更新するといった運用設計も考えてみたいと思っています。

まとめ

私はE2Eテストを作成することが初めてで難しいものだと構えていましたが、StepCIのようなツールを使えばトークン管理・テンプレート処理・OpenAPI活用といった機能で簡単に導入できました。
また今回のE2Eテストの導入を通して「テストでなにをするのか(責務)」を明確にし、CI上でのテスト用データの管理などを配慮した運用設計を行うことを学びました。
この記事が同じような課題を抱える方の参考になれば嬉しいです。

脚注
  1. https://www.archunit.org/ ↩︎

  2. https://docs.stepci.com/guides/setup-teardown.html ↩︎

  3. https://github.com/stepci/liquidless ↩︎ ↩︎

  4. https://docs.stepci.com/guides/testing-http.html#captures ↩︎

  5. https://docs.stepci.com/import/openapi.html ↩︎

WealthNavi Engineering Blog

Discussion