Step Functions ・サーバーレス環境のテストを考える(ローカルでテストする?しない?)

記事タイトルとURLをコピーする

こんにちは😸
カスタマーサクセス部の山本です。

Step Functions のテストを考えてみました。
確か Step Functions Local というものがあったと思い、調べてみるとサポートされなくなっていました。

参考:Step Functions Local を使用したステートマシンのテスト (サポートされていません) - AWS Step Functions

Step Functions Local はサポートされていません
Step Functions Local は機能パリティを提供しておらず、サポートされていません。

テスト目的で Step Functions をエミュレートするサードパーティーソリューションを検討することもできます。

Step Functions Local がサポートされなくなった理由

Step Functions Local は機能パリティを提供しておらず、サポートされていません。

「機能パリティ」ってなんだろう?と思い原文を読んだところ、「実際の Step Functions の機能との整合性」という感じでした。
Step Functionsは、新しいインテグレーション(200以上のAWSサービスとの連携)、組み込み関数、実行タイプ(Express Workflowsなど)、Jsonata式などが継続的に追加され、非常に多機能になっています。Step Functions Local はそれらの機能を取り込み切れていないということのようです。
Step Functions ではできるんだけど、Step Functions Local だとできない、みたいなことがありそうですね。

「Step Functions をエミュレートするサードパーティーソリューション」とは

テスト目的で Step Functions をエミュレートするサードパーティーソリューションを検討することもできます。

こちらはおそらく、LocalStack のことかなと思います。 LocalStackは、AWS の様々なサービスを開発者のローカルマシン上で再現するためのオープンソースのモック(模倣)フレームワークです。これにより、開発者は実際のAWS環境に接続することなく、AWSに依存するアプリケーションをオフラインで開発・テストできます。

Step Functions のテストで必要な観点

LocalStack を使用するのか検討するために、まずはテストの観点を洗い出してみましょう。
AWS Step Functionsのテストで必要な観点は、主に以下の4つのレベルに分けられると思います。 それぞれのレベルでテストの目的と方法が異なります。


1. Step Functions 単体テスト

個々のLambda関数やAPIなど、ステートマシンを構成する各コンポーネントが正しく動作するかを検証します。

  • 何をテストするか?
    • ビジネスロジック: 各Lambda関数やAPIが、与えられた入力(event)に対して期待される処理を行い、正しい出力を返すか。
    • 正常系: 正常な入力が与えられた場合に、意図した通りの処理が完了するか。
    • 異常系: 不正な入力、外部サービスのタイムアウト、予期せぬエラーなどが発生した場合に、適切にエラーハンドリング(例: 例外をスローする)できるか。

2. Step Functions 結合テスト

ステートマシン全体のロジックが正しく動作するかを検証します。各ステートが連携し、期待通りに状態遷移するかを確認します。

  • 何をテストするか?
    • 状態遷移: あるステートからの出力が、次のステートの入力として正しく渡されているか。
    • 分岐ロジック (Choice ステート): 条件に応じて、正しく次のステートに遷移するか。
    • 並列処理 (Parallel ステート): すべてのブランチが期待通りに実行されるか。
    • エラーハンドリング (Retry, Catch): 特定のステートでエラーが発生した場合に、リトライ処理やエラーパスが正しく機能するか。
    • 待ち時間 (Wait ステート): 指定された時間、正しく待機するか。

3. Step Functions 総合テスト(End-to-End)テスト

実際のAWS環境で、ステートマシンが他のAWSサービス(API Gateway, S3, DynamoDBなど)や外部システムと連携して、一連のビジネスプロセス全体が正しく機能するかを検証します。

  • 何をテストするか?
    • トリガー: API GatewayへのリクエストやS3へのファイルアップロードなど、ステートマシンを起動するトリガーが正しく機能するか。
    • 外部連携: データベースへの書き込み、外部APIの呼び出し、メッセージキューへの送信などが、ステートマシンの実行結果として正しく行われているか。
    • IAMロールと権限: ステートマシンや各Lambda関数に割り当てられたIAMロールが、他のAWSリソースにアクセスするために必要な権限を過不足なく持っているか。
    • 非機能要件: タイムアウト設定は適切か、全体のパフォーマンスに問題はないか。

4. Step Functions 静的解析

ステートマシンの定義(Amazon States Language - ASL)自体に問題がないかを確認します。

  • 何をテストするか?
    • 構文の妥当性: ASLのJSON定義が文法的に正しいか。
    • 設定ミス: リソースのARNが正しいか、IAMの権限定義に誤りがないか。
    • ベストプラクティス: AWSが推奨する記述方法に従っているか。

これらの観点を組み合わせることで、Step Functionsで構築されたワークフローの品質と信頼性を高めることができます。

Step Functions が用意しているテスト TestState API (マネジメントコンソール)

Step Functions がサービスとして提供している唯一のツールとして、TestState API があります。
変更したステートマシンの定義を保存せずにステートマシンの定義内にある定義を1つずつテストできます。
Map 状態や Parrallel 状態をサポートしていないなど、制限があります。
また、実際に API や Lambda は実行されてしまう点にも注意が必要です。
開発環境でのデバッグ時に便利ですね。

Step Functionsコンソールのワークフロー編集画面でステートを選択した際に表示される「テスト状態(Test state)」ボタンを使用します。

必要に応じて入力を自分で入れます。「テスト開始」を押します。

失敗時:

成功時:

実行結果画面からもテストできます。

サーバーレス環境のテスト(ローカルでテストする?しない?)

Lambda のドキュメントにテスト方法の記載があるので、読んだ内容を要約してみます。

このドキュメントの核心は、「サーバーレスアプリケーションでもこれらの伝統的なテストは行うが、その大部分は実際のクラウド環境で実行することが最も正確で信頼できる」という点です。

単体テスト (Unit Test) の観点

ドキュメントでは、単体テストを「分離されたコードブロック」のロジック検証と位置づけています。

  • 推奨される手法 Lambda固有の処理(イベントデータの解析など)と、中心となるビジネスロジックを分離することが推奨されています。これにより、ビジネスロジック部分をクラウドサービスへの依存なく、高速にテストできます。例えば Lambda起動時に event を受け取り他の関数に渡すためのハンドラー関数についてはクラウド上でテストします。一方、ハンドラー関数から受け取ったデータを計算処理する部分はローカルで実行します。

  • モックを使用して外部 API の実行結果を模したオブジェクトを返却させ、代替する: AWS 以外の API を呼び出すような複雑なロジック(財務計算など)のテストには、モック(外部サービスを模倣するオブジェクト)の使用が有効です。ハンドラー関数からデータを受け取り、計算を行ってハンドラー関数に戻すような処理です。この処理の中で外部 API などを使用する場合は、外部 API の実行結果を模したオブジェクトを返却するようにモックなどを使用すると良いでしょう。

  • 注意点 ただし、ローカルでの単体テストが成功しても、クラウド上ではメモリ不足やタイムアウト、権限設定の問題で失敗する可能性があるため、クラウドでのテストも不可欠であると強調されています。


結合テスト (Integration Test) の観点

ドキュメントでは、このテストがサーバーレスにおいて最も重要だと強調されています。「2つ以上のコンポーネントやサービスが相互作用する」部分を検証します。

  • 推奨される手法 必ずクラウド環境で実行することが強く推奨されます。なぜなら、Lambda関数とSQSキュー、API GatewayとLambda、LambdaとDynamoDBデータベースといったサービス間の連携をテストする必要があるからです。

  • 検証対象 コードのロジックだけでなく、サービス間のIAM権限(セキュリティ設定)、サービス設定クォータ(上限値)などが正しく構成されているかを検証することが目的です。ローカルのモックやエミュレータでは、これらの検証は不可能です。


統合テスト (End-to-End Test) の観点

ドキュメントでは、統合テストを「アプリケーション全体の動作を検証する、特殊なタイプの結合テスト」と定義しています。

  • 推奨される手法 これも必ずクラウド環境で実行します。例えば、ユーザーがAPIを叩いてから、イベントが複数のサービスを通り抜け、最終的にデータベースに正しく記録されるまでの一連の流れ(ワークフロー)全体をテストします。

  • 検証対象 個々の連携だけでなく、インフラ全体が正しく設定され、ビジネスシナリオ全体が期待通りに流れるかを確認します。この段階では、状態やロジックが複雑になるため、モックの使用は避けるべきだとされています。


開発・テスト環境のアプローチまとめ

開発者がテストを実施するにあたり、どのような環境で、どういうアプローチを取るべきかについてまとめます。

結論:統制の取れたAWS環境とツールの活用が鍵

最適なアプローチは、「組織的な統制を効かせた上で開発者ごとにAWSアカウントを用意し、開発者はAWS Toolkitなどを活用してローカル開発の速度感とクラウド環境の信頼性を両立させる」ことです。


1. 開発環境の選択肢:AWS上かローカルか?

開発・テスト環境にはそれぞれメリットとデメリットがあります。

  • AWS上での開発・テスト

    • メリット
      • 信頼性が高い: AWS公式が推奨する方法で、実際のサービスとの機能の差異がなく、タイムアウトやサービスクォータといった環境依存の設定も正確にテストできます。
    • デメリット
      • 開発サイクルが遅い: 軽微な修正でもデプロイに時間がかかる場合があります。
  • ローカル環境(エミュレータなど)での開発・テスト

    • メリット
      • 開発サイクルが速い: 実環境から切り離されているため、修正からテストまでのサイクルを迅速に回せます。
    • デメリット
      • 環境差異のリスク: AWS環境との完全な互換性は保証されず、デプロイ後にエラーが発生する可能性があります。
      • 制約: エミュレータの利用規約や料金、再現できない機能(IAM権限など)に注意が必要です。

📝 補足: どちらの環境でも、外部APIの連携などはモック(模擬データ)を使う必要があり、完全な再現が難しいケースもあります。


2. AWS環境の提供方法とガバナンス

AWSを開発環境として利用する場合、その提供方法が重要になります。 ステージング環境・本番環境にデプロイするまえに検証するアカウントを用意すると良いと思います。

  • 推奨:開発者ごとに専用AWSアカウントを払い出す

    • これが最も理想的です。ただし、個人の設定ミスによる権限漏洩などのリスクを防ぐため、組織的な統制が必須です。
    • 統制のポイント
      • AWS Organizations: 組織全体のアカウントを管理。
      • セキュリティサービス: GuardDutyCost Anomaly Detectionで不正な操作やコスト異常を監視。
      • リソース共有: NAT Gatewayなど共通で利用するインフラは共有し、コストを最適化。
  • 代替案:共用の開発アカウントを利用する

    • 個人アカウントを用意できない場合の次善策です。
    • 注意点
      • リソース名の命名規則を徹底し、他の開発者のリソースと衝突しないよう工夫が必要です。
      • この場合も、セキュリティの一元管理は欠かせません。

開発者ごとに AWS アカウントを用意しつつ、全開発者がログインできるような共用の AWS アカウントもあると進めやすいかなと思います。


3. ローカルとクラウドを繋ぐ開発ツール

AWS Toolkit for Visual Studio Code のようなツールを利用することで、両環境の「良いとこ取り」が可能です。

  • 特徴
    • ローカルエディタ上でコードを書きながら、クラウド上にリソースを作成・テストできます。これにより、ローカル開発のような速度感を維持しつつ、AWS環境の信頼性を得られます。
  • 注意点
    • クレデンシャル管理: VS Codeにアクセスキーなどを設定するため、その管理には細心の注意が必要です。
    • 設定の差異: リージョン設定など、マネジメントコンソールとは異なる部分に気を付ける必要があります。

これまでのまとめ

この記事では、まず Step Functions Local がサポートを終了した背景について触れました。その理由は、日々進化する実際の Step Functions の豊富な機能に Step Functions Local が追従できず、「機能パリティ(機能の整合性)」を保てなくなったためです。

代替案として LocalStack のようなサードパーティーツールが存在するものの、テストには複数の観点があることを整理しました。

  1. 単体テスト: Lambda関数などの個々の部品のロジックを確認する。
  2. 結合テスト: ステートマシン全体の流れや状態遷移を確認する。
  3. 総合テスト (E2E): 実際のAWS環境で、他のサービスとの連携を含めた全体の動きを確認する。
  4. 静的解析: ステートマシンの定義ファイルそのものに誤りがないかを確認する。

特にAWS Lambdaの公式ドキュメントでは、サービス間の連携やIAM権限といったクラウド固有の設定を検証するために、結合テスト以上のテストは「実際のクラウド環境で実行すること」が最も信頼性が高いと強調されています。

つまり、ビジネスロジックの核となる部分はローカルで迅速にテストし、サービス連携を含む全体の振る舞いはクラウドで確実にテストする、という使い分けが重要になります。 クラウド環境を適切に開発者に提供する検討も必要になります。
では、この「ローカルでの開発」と「クラウドへのデプロイ・テスト」をスムーズに行うにはどうすればよいのでしょうか。その強力な味方となるのが、次に紹介する AWS Toolkit for Visual Studio Code です。


ローカル開発とクラウドを繋ぐ AWS Toolkit for Visual Studio Code

AWS Toolkit for Visual Studio Code は、多くの開発者が利用しているエディタ「Visual Studio Code(VS Code)」の拡張機能です。これを導入することで、VS Code を離れることなく、ローカルでのサーバーレスアプリケーション開発から、AWS環境へのデプロイ、デバッグまでをシームレスに行うことができます。

主な機能とメリット

1. Step Functions ステートマシンの可視化

AWS Toolkit の最も便利な機能の一つが、ステートマシンの定義言語である ASL (Amazon States Language) をリアルタイムでグラフとして可視化してくれる機能です。

コードを書きながら、ワークフローがどのような流れになるのかを視覚的に確認できるため、複雑な分岐や並列処理も直感的に設計できます。これにより、定義ファイルの記述ミスを大幅に減らすことができます。

2. Lambda 関数のローカルでのテストとデバッグ

AWS ToolkitAWS SAM (Serverless Application Model) と連携し、Lambda関数をローカル環境で直接実行・デバッグする機能を提供します。

  • ローカル実行: VS Code上でテスト用のイベント(JSONデータ)を作成し、ワンクリックでLambda関数を実行できます。これにより、クラウドにデプロイする前に、関数の基本的なロジックを素早く検証できます。
  • ステップ実行デバッグ: ブレークポイントを設定し、変数の内容を確認しながら一行ずつコードを実行できるため、複雑な処理のデバッグが非常に効率的になります。

これにより、前述の「Lambda単体テスト」を高速に回すことが可能になります。

3. クラウドへの簡単なデプロイと動作確認

ローカルでの開発とテストが完了したら、VS Codeのコマンドパレットや右クリックメニューから、数ステップでアプリケーションをAWS環境にデプロイできます。

さらに、デプロイ後の動作確認も簡単です。AWS Toolkit のエクスプローラーから CloudWatch Logs にアクセスし、実行ログを直接確認できるため、クラウド上で発生した問題の調査もVS Code内で完結します。

AWS Toolkit for Visual Studio Code を試してみる

拡張を検索する画面で検索しても大丈夫ですし、以下リンクで配布しています。

[install] をクリックしてインストールします。

AWS CLI / SAM CLI のインストールが必要なようなので、インストールしていきます。

<ctrl> + <shift> + p を押し、コマンドパレットで AWS: Create Credentials Profile と入力すると、認証情報を設定できます。

Step Functions

Resource Explorer を開くと、様々なサービスのリソースを閲覧できます。
私が作成した Step Functions のステートマシンを参照してみましょう。

TestState API を試してみましょう。IAM Role が自動入力されない点がマネジメントコンソールとは異なりました。

正常に実行できました。

Lambda を1つ追加しました。

[Save & Deploy] を押します。

下の[Quick Update]を押します。

対象のステートマシンを選択します。

[output] セクションにアップデートの状況が表示されます。

マネジメントコンソールを見ると Lambda が追加になっていました。
他にも引数の追加などがマネジメントコンソールと同様に実施できました。
]

コードスニペットが付いていたりするのは便利でした。
Step Functions についてはローカル実行する方法や SAM への変換機能がなさそうです。

Lambda

Lambda 関数を開くと、ソースコードが表示されています。

右上の再生マークを押すと、ローカルで実行できるようです。

ローカルにインストールしている Python3.13 で実行されました。

ハンドラ関数を呼び出すコードを追加して、ローカルで実行してみます。
確かに細かい修正はここで行うことができますね。

ブレークポイントも設定できます。

右下に AWS 側の Lambda 関数も更新するボタンがあります。 [ctrl] +s を押しても表示されます。

AWSクラウド側で実行することもできます。

実行できました。

SAM 変換もできます。

SAM 変換を実行して 5 秒くらい待つとスタック名を入力するポップアップが出ます。入力しないでそのままにしているとエラーになって失敗します。

template が出来ました。

  • template.yaml
Transform: AWS::Serverless-2016-10-31
Parameters: {}
Resources:
  LambdaFunctionFunctionprintevent:
    Type: AWS::Serverless::Function
    Properties:
      MemorySize: 128
      Description: ''
      Timeout: 3
      RuntimeManagementConfig:
        UpdateRuntimeOn: Auto
      Handler: lambda_function.lambda_handler
      Role: arn:aws:iam::111111111111:role/service-role/print-event-role-73708f7q
      FileSystemConfigs: []
      FunctionName: print-event
      Runtime: python3.13
      PackageType: Zip
      LoggingConfig:
        LogFormat: Text
        LogGroup: /aws/lambda/print-event
      RecursiveLoop: Terminate
      EphemeralStorage:
        Size: 512
      Architectures:
        - x86_64
      Tracing: PassThrough
      CodeUri: LambdaFunctionFunctionprintevent

まとめ

このように AWS Toolkit for Visual Studio Code を活用することで、開発者は以下のサイクルを効率的に実現できます。

  • ローカルで完結する小さなテストは従来通りホストマシン上で完結
  • Function 単位の動作確認も Toolkit を使って IDE 内で完結できる
  • 実際のクラウド環境を使った複合的な動作確認も、Toolkit を使えば開発者の個人アカウントに簡単にデプロイし、検証できる

VS Code で AWS の実環境への操作が完結するのは良いですね。WEB ブラウザとは少し違うので慣れは必要だと思います。 改善点が何かあるとすれば、Git リポジトリとの連携がしやすいと良いかなと思いました。

Step Functions やサーバーレスアプリケーションのテストについて考えてみました。

参考

余談

今日の写真は北アルプス双六岳の天空の滑走路です。正面に槍ヶ岳が見えます。

山本 哲也 (記事一覧)

多分インフラエンジニアです。データ分析に興味あります。

山を走るのが趣味です。今年は 100 マイルレース完走します。