SAP HANA Development
SAP HANAアプリのユニットテストとデバッグ方法:SQLScript・XSJS・統合処理の切り分け
SAP HANA on-premiseで開発したアプリケーションを対象に、ユニットテストの設計、SQLScriptのデバッグ、XSJSや外部アプリケーションとの統合テスト、失敗時のログ確認までを実務手順として解説します。
SAP HANA上のアプリケーションで不具合を切り分けるには、データ、データベースロジック、アプリケーションサービス、接続設定を分けて検証します。最初から画面操作だけで確認すると、SQLScriptの結果不整合とアプリケーション側の変換処理を区別しにくくなります。
この記事では、SAP HANA on-premiseを対象に、SQLScriptプロシージャやテーブルファンクション、XSJSなどの処理を段階的にテストする方法を説明します。SAP HANA database explorerやSAP HANA cockpitを使った確認方法も、用途に応じて整理します。
テスト対象と実行環境を整理する
最初に、テスト対象を次の単位に分けます。
- データ層:テーブル、ビュー、カラムストアのデータ、制約
- ロジック層:SQLScriptプロシージャ、テーブルファンクション、計算ビュー
- サービス層:XSJS、Node.js、Javaなどのアプリケーションサービス
- 接続層:データベースユーザー、ロール、接続先、トランザクション
- 画面・API層:入力値、レスポンス形式、エラー表示
テスト用スキーマまたはテスト用コンテナを用意し、開発用データと本番データを混在させない構成にします。テストデータには、通常値だけでなく、空値、重複値、境界値、存在しないキー、最大長に近い文字列を含めます。
テストケースごとに、入力条件、実行対象、期待結果、実際の結果、再現手順を記録します。特に日付、タイムゾーン、通貨、小数精度、NULLの扱いは、環境差による不具合が発生しやすい項目です。
開発全体の構成を先に確認したい場合は、SAP HANA開発の全体像でデータモデル、SQLScript、アプリケーション層の関係を確認できます。
ユニットテストの設計
ユニットテストでは、複数の処理をまとめて実行するよりも、1つの責務を持つオブジェクトに対して入力と出力を固定します。たとえば、売上金額を計算するSQLScriptなら、数量、単価、割引率、税率を明示し、期待する金額を比較します。
テストデータを準備する際は、テスト前に初期状態を作り、テスト後に変更を取り消せるようにします。更新処理を含む場合は、テスト専用のトランザクション境界を設け、次のテストへデータが残らないようにします。
SQLScriptプロシージャの単体テストでは、次の観点を分けて確認します。
- 入力パラメータの妥当性
- SELECT結果の件数と値
- JOIN条件による重複や欠落
- NULLと空文字の扱い
- エラー条件での例外処理
- 更新対象と更新件数
- 出力テーブルや出力パラメータの構造
テーブルファンクションでは、入力に対して返却される列の順序、データ型、NULL許容、レコード件数を確認します。計算ビューを呼び出す処理では、分析権限や入力パラメータによって結果が変わるため、権限を付与したユーザーと付与していないユーザーの両方で確認します。
SQLScriptのプロシージャ設計や呼び出し方法を整理する場合は、SAP HANA SQLScriptプロシージャの実装方法も参照してください。
XSJSとサービス処理をテストする
XSJSなどのサービス処理では、データベースロジックだけでなく、HTTPリクエストとレスポンスの境界を検証します。正常系では、必須パラメータをすべて指定したリクエストを送り、HTTPステータス、レスポンス形式、文字コード、返却件数を確認します。
異常系では、次の入力を個別に送ります。
- 必須パラメータがないリクエスト
- 数値項目に文字列を指定したリクエスト
- 存在しないキーを指定したリクエスト
- 権限のないユーザーによるリクエスト
- 大量件数を要求するリクエスト
- 同じ更新を複数回送るリクエスト
サービス層でエラーを握りつぶすと、呼び出し側には成功に見える状態が発生します。データベースで発生した例外を、意味のあるHTTPステータスと安全なエラーメッセージへ変換し、詳細な内部情報はサーバー側のログで確認できるようにします。
外部アプリケーションと連携する処理では、接続ユーザーの権限、接続先、コミットのタイミング、タイムアウトを別々に検証します。接続が成功していても、対象オブジェクトへの権限不足やロールの割り当てによって処理が失敗するため、実行ユーザーを明示して確認します。
SQLScriptをデバッグする
SQLScriptのデバッグでは、最終結果だけでなく、中間結果を観測できる形にします。複雑なSELECTを一度に実行せず、CTE、JOIN、集計、条件分岐を段階的に実行し、各段階の件数と代表的な値を確認します。
SAP HANA database explorerでは、対象のSQLScriptプロシージャを直接実行し、入力パラメータを固定して結果を確認できます。まず読み取り処理をテストし、次に更新処理をテストします。更新処理の確認では、実行前後の対象件数と更新日時を比較します。
デバッグ時は、次の観測点を追加すると原因を絞り込みやすくなります。
- JOIN前後のレコード件数
- WHERE条件を適用する前後の件数
- 集計キーごとの重複数
- NULLが発生する列
- 入力パラメータの値とデータ型
- 分岐ごとの実行結果
- 更新対象の主キー
一時的なログ出力を追加した場合は、原因確認後に削除または無効化します。大量データをログへ出力すると、処理時間、ログ容量、機密情報の取り扱いに影響するため、主キーや件数など必要最小限の情報に限定します。
性能問題が疑われる場合は、結果の正しさを確認した後に実行計画、フィルタ条件、不要な列の読み込み、集計処理を調べます。性能の確認手順は、SAP HANA開発者向けパフォーマンスチューニングにまとめています。
xsunitを使ったテストの進め方
xsunitを利用する環境では、テスト対象のロジックとテストケースを分離して管理します。テストケースには、準備、実行、検証、後処理の順序を持たせます。
基本的な流れは次のとおりです。
- テスト用スキーマまたはテーブルへ初期データを投入する
- 対象プロシージャや関数を入力値付きで実行する
- 期待結果と実際の結果を比較する
- 更新処理がある場合は、変更内容を検証する
- テスト後にデータを初期状態へ戻す
比較では、レコード件数だけでなく、主キー、金額、日付、ステータス、NULLの有無を検証します。順序が保証されない結果を比較する場合は、主キーや明示的なソート条件を使って結果を安定させます。
テストが失敗した場合は、テストフレームワークの失敗表示だけで判断せず、同じ入力値をSAP HANA database explorerで直接実行します。直接実行で成功し、xsunitで失敗する場合は、テストデータの初期化、実行ユーザー、トランザクション境界、スキーマ指定を確認します。
テスト名には、対象機能と条件を含めます。たとえば、calculate_total_with_empty_discount のように、正常系か異常系かをテスト名から判断できる形にすると、失敗箇所の特定が容易になります。
エラーとログを切り分ける
エラー発生時は、最初にエラーコード、メッセージ、発生時刻、実行ユーザー、対象オブジェクトを記録します。同じメッセージでも、権限不足、入力値不正、接続切断、ロック、データ不整合では確認箇所が異なります。
SAP HANA cockpitでは、システムのアラート、サービス状態、トレース、メモリやCPUの状況を確認できます。アプリケーションのログとデータベース側のトレースを、同じ時刻情報で照合します。
SAP HANA database explorerでは、SQL文を単独で実行し、オブジェクト名、スキーマ、パラメータ、実行ユーザーを確認します。SQL文が単独で成功する場合は、サービス層の接続設定、パラメータ変換、コミット処理を調べます。単独実行でも失敗する場合は、SQLScript、データ、権限の順に絞り込みます。
エラーの切り分けでは、次の順序が有効です。
- 同じ入力値で再現する
- 最小のSQL文または最小のサービス呼び出しにする
- 実行ユーザーとスキーマを固定する
- 入力値と中間結果を確認する
- データベース単独実行とアプリケーション経由を比較する
- ログとトレースを時刻で照合する
- 修正後に回帰テストを実行する
権限とテストデータを確認する
開発者のユーザーで成功し、アプリケーションの接続ユーザーで失敗する場合は、オブジェクト権限、ロール、実行者権限、スキーマ参照を確認します。特に、定義者権限と呼び出し者権限の違いは、プロシージャやビューの実行結果に影響します。
テストデータは、個人情報や業務上の機密情報をそのまま複製せず、テスト目的に必要な値へ置き換えます。マスキング後も、桁数、NULL、重複、参照関係、日付範囲など、処理に必要な性質を維持します。
並列実行を含む機能では、同じキーを同時に更新するケース、片方がロールバックするケース、読み取り中に更新が発生するケースを確認します。ロックやタイムアウトが発生した場合は、長時間トランザクション、未コミット更新、アプリケーションの再試行処理を確認します。
回帰テストとCIに組み込む
修正が完了したら、失敗したテストだけでなく、関連する正常系と異常系を再実行します。SQLScriptの共通関数やテーブル構造を変更した場合は、直接呼び出すプロシージャ、テーブルファンクション、サービスAPIまで対象を広げます。
CIへ組み込むテストでは、環境に依存する値を外部設定に分離し、接続情報やパスワードをソースコードへ記録しません。テスト結果には、コミット識別子、実行時刻、対象コンポーネント、失敗したテスト名、エラー内容を含めます。
失敗時のログは、再現に必要な範囲で保存します。入力値に機密情報が含まれる場合はマスキングし、ログ保存期間とアクセス権を定めます。成功率だけでなく、テスト実行時間と不安定なテストの発生数も継続的に確認します。
実務で使えるトラブルシューティング手順
次の表を、最初の切り分けに利用できます。
| 症状 | 最初に確認する項目 | 次の確認 |
|---|---|---|
| SQLScriptが結果を返さない | 入力パラメータ、WHERE条件、対象スキーマ | JOIN条件、データの有無、権限 |
| 結果件数が多い | JOINキー、重複データ、集計単位 | 主キー関係、フィルタ適用位置 |
| XSJSの呼び出しが失敗する | HTTPステータス、リクエスト形式 | 接続設定、実行ユーザー、サーバーログ |
| 画面だけで値が異なる | リクエスト変換、日時、数値形式 | APIレスポンス、ブラウザ側の変換 |
| 開発者だけ成功する | 接続ユーザー、ロール、スキーマ | オブジェクト権限、実行者権限 |
| テストが時々失敗する | テストデータの初期化、共有状態 | 並列実行、時刻依存、トランザクション |
| 本番に近いデータで遅い | 実行件数、読み込み列、集計 | 実行計画、インデックス、処理分割 |
最終的には、再現条件、原因、修正内容、検証したテストケースを1つの記録にまとめます。同じ障害が再発したときに、環境の記憶に頼らず再検証できる状態を作ることが重要です。