abap-unit-testing について
abap-unit-testingは、ABAP Unitテストの作成ガイドとなるスキルです。業務ロジック、CDS、SQL依存コード、RAPのテスト方法に加え、アサーションやテストダブル、テスト環境を解説します。
主な機能
- 01ABAP Unitテストクラスの構成
- 02アサーションとAAAパターン
- 03依存性注入とテストダブル
- 04CDSとOSQLのテスト環境
- 05RAP BOテストダブル
活用シーン
- 01業務ロジックと検証ルールのテスト
- 02データベース依存コードのスタブ化
- 03CDSビュー計算のテスト
- 04RAP動作実装の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ likweitan/ abap-skills --skill abap-unit-testingインストール後、Claude Code で/abap-unit-testingを入力して読み込まれたか確認します。
同梱ファイルreferences/test-environment-examples.md
詳細
ABAP ユニットテスト
テストクラスのセットアップ、アサーション、テストダブル、モックフレームワーク、CDS、SQL、RAP のテスト環境を含む、効果的な ABAP Unit テストの作成ガイドです。
ワークフロー
-
テストの目的を特定します:
- クラスメソッドのビジネスロジックをテストする
- CDS ビューエンティティをテストする
- RAP BO の振る舞いの実装をテストする
- SQL テストダブルを使ってデータベース依存のロジックをテストする
- 外部依存関係のテストダブルを設定する
-
適切なアプローチを選択します:
- 純粋なロジック(依存関係なし)には直接ユニットテストを使用する
- モック可能な依存関係にはコンストラクター/セッターインジェクションを使用する
- CDS ビューのテストには CDS テスト環境を使用する
- SQL 依存コードには OSQL テスト環境を使用する
- RAP の振る舞いのテストには RAP BO テストダブルを使用する
-
AAA パターンに従います:準備 → 実行 → 検証
-
テストを独立させます:テストが永続データや外部システムに依存しないようにします
テストクラスの基本
テストクラスの定義
"! Test class for ZCL_MY_CLASS
CLASS ltc_my_class DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA cut TYPE REF TO zcl_my_class. "Class Under Test
CLASS-METHODS class_setup. "Once before all tests
CLASS-METHODS class_teardown. "Once after all tests
METHODS setup. "Before each test
METHODS teardown. "After each test
METHODS test_calculate_total FOR TESTING.
METHODS test_validate_input FOR TESTING.
METHODS test_empty_input FOR TESTING RAISING cx_static_check.
ENDCLASS.
CLASS ltc_my_class IMPLEMENTATION.
METHOD class_setup.
" One-time setup for all tests in this class
ENDMETHOD.
METHOD class_teardown.
" One-time cleanup
ENDMETHOD.
METHOD setup.
" Create fresh instance before each test
cut = NEW #( ).
ENDMETHOD.
METHOD teardown.
" Cleanup after each test
ENDMETHOD.
METHOD test_calculate_total.
" Arrange
DATA(lv_quantity) = 5.
DATA(lv_price) = CONV decfloat34( '10.50' ).
" Act
DATA(lv_result) = cut->calculate_total(
iv_quantity = lv_quantity
iv_price = lv_price ).
" Assert
cl_abap_unit_assert=>assert_equals(
act = lv_result
exp = CONV decfloat34( '52.50' )
msg = 'Total should be quantity * price' ).
ENDMETHOD.
METHOD test_validate_input.
cl_abap_unit_assert=>assert_true(
act = cut->validate_input( 'VALID_INPUT' )
msg = 'Valid input should return true' ).
ENDMETHOD.
METHOD test_empty_input.
TRY.
cut->validate_input( '' ).
cl_abap_unit_assert=>fail( msg = 'Should have raised exception' ).
CATCH zcx_validation_error INTO DATA(lx_error).
cl_abap_unit_assert=>assert_bound(
act = lx_error
msg = 'Exception should be raised for empty input' ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
テストクラスの属性
| 属性 | オプション | 目的 |
|---|---|---|
DURATION | SHORT / MEDIUM / LONG | 想定される実行時間。SHORT は 1 秒未満(CI のデフォルト) |
RISK LEVEL | HARMLESS / DANGEROUS / CRITICAL | システムデータへの影響。HARMLESS は DB に変更を加えません |
テストメソッドの追加指定
| 追加指定 | 目的 |
|---|---|
FOR TESTING | メソッドをテストメソッドとして指定します |
RAISING cx_static_check | 例外の伝播を許可します(未処理の例外が発生するとテストは失敗します) |
CL_ABAP_UNIT_ASSERT — アサーションメソッド
| メソッド | 目的 | 例 |
|---|---|---|
assert_equals | 値が等しいこと | assert_equals( act = result exp = 42 ) |
assert_true | 真偽値が true であること | assert_true( act = lv_flag ) |
assert_false | 真偽値が false であること | assert_false( act = lv_flag ) |
assert_initial | 値が初期値であること | assert_initial( act = lt_table ) |
assert_not_initial | 値が初期値でないこと | assert_not_initial( act = lt_result ) |
assert_bound | 参照がバインドされていること | assert_bound( act = lo_instance ) |
assert_not_bound | 参照がバインドされていないこと | assert_not_bound( act = lo_ref ) |
assert_differs | 値が異なること | assert_differs( act = val1 exp = val2 ) |
assert_char_cp | 文字パターンに一致すること | assert_char_cp( act = lv_text exp = '*error*' ) |
assert_char_np | 文字パターンに一致しないこと | assert_char_np( act = lv_text exp = '*secret*' ) |
assert_number_between | 数値が範囲内であること | assert_number_between( number = val lower = 1 upper = 10 ) |
assert_table_contains | テーブルに行が含まれていること | assert_table_contains( line = wa table = lt_result ) |
assert_table_not_contains | テーブルに行が含まれていないこと | assert_table_not_contains( line = wa table = lt_result ) |
assert_return_code | sy-subrc の確認 | assert_return_code( act = sy-subrc exp = 0 ) |
fail | テストを強制的に失敗させる | fail( msg = 'Should not reach here' ) |
よくあるアサーションパターン
" Check table has expected number of entries
cl_abap_unit_assert=>assert_equals(
act = lines( lt_result )
exp = 3
msg = 'Expected 3 result entries' ).
" Check exception message
TRY.
cut->some_method( ).
cl_abap_unit_assert=>fail( msg = 'Expected exception' ).
CATCH zcx_my_exception INTO DATA(lx).
cl_abap_unit_assert=>assert_equals(
act = lx->get_text( )
exp = 'Expected error message' ).
ENDTRY.
" Check that table contains a specific key
cl_abap_unit_assert=>assert_table_contains(
line = VALUE zstructure( key_field = 'ABC' )
table = lt_result
msg = 'Result should contain entry ABC' ).
依存性注入とテストダブル
コンストラクター注入パターン
" Production interface
INTERFACE zif_data_provider.
METHODS get_data
RETURNING VALUE(rt_data) TYPE ztab_data.
ENDINTERFACE.
" Production class with injectable dependency
CLASS zcl_processor DEFINITION.
PUBLIC SECTION.
METHODS constructor
IMPORTING io_provider TYPE REF TO zif_data_provider OPTIONAL.
METHODS process
RETURNING VALUE(rv_result) TYPE string.
PRIVATE SECTION.
DATA mo_provider TYPE REF TO zif_data_provider.
ENDCLASS.
CLASS zcl_processor IMPLEMENTATION.
METHOD constructor.
mo_provider = COND #(
WHEN io_provider IS BOUND THEN io_provider
ELSE NEW zcl_default_provider( ) ).
ENDMETHOD.
METHOD process.
DATA(lt_data) = mo_provider->get_data( ).
" Process data...
ENDMETHOD.
ENDCLASS.
テストダブル(手動モック)
" Test double implementing the interface
CLASS ltd_data_provider DEFINITION FOR TESTING.
PUBLIC SECTION.
INTERFACES zif_data_provider.
DATA mt_test_data TYPE ztab_data.
ENDCLASS.
CLASS ltd_data_provider IMPLEMENTATION.
METHOD zif_data_provider~get_data.
rt_data = mt_test_data.
ENDMETHOD.
ENDCLASS.
" Test class using the double
CLASS ltc_processor DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA cut TYPE REF TO zcl_processor.
DATA mo_provider TYPE REF TO ltd_data_provider.
METHODS setup.
METHODS test_process_with_data FOR TESTING.
ENDCLASS.
CLASS ltc_processor IMPLEMENTATION.
METHOD setup.
mo_provider = NEW #( ).
cut = NEW #( io_provider = mo_provider ).
ENDMETHOD.
METHOD test_process_with_data.
" Arrange — configure test double
mo_provider->mt_test_data = VALUE #(
( key = '1' value = 'A' )
( key = '2' value = 'B' ) ).
" Act
DATA(lv_result) = cut->process( ).
" Assert
cl_abap_unit_assert=>assert_not_initial( act = lv_result ).
ENDMETHOD.
ENDCLASS.
CDS テスト環境
cl_cds_test_environment=>create( i_for_entity = 'ZI_ENTITY' ) を使用して、CDS ビューのすべてのデータソースをスタブ化します。insert_test_data( ) でテストデータを挿入し、setup で clear_doubles( ) を呼び出してクリアし、class_teardown で destroy( ) を呼び出します。
OSQL(Open SQL)テスト環境
cl_osql_test_environment=>create( i_dependency_list = ... ) を使用して、SQL に依存するクラスのテスト用に特定の DB テーブル/ビューをスタブ化します。ライフサイクルのパターンは CDS テスト環境と同じです。
RAP BO テストダブル
- トランザクションバッファーのテストダブル(
cl_botd_txbufdbl_bo_test_env):EML を介して RAP BO を利用するコードのテストに使用します - モック EML API(
cl_botd_mockemlapi_bo_test_env):モックの応答を設定して、RAP ハンドラーのメソッド実装をテストするために使用します
テストシーム(レガシーコード)
本番コードで TEST-SEAM/END-TEST-SEAM を使用し、テストで TEST-INJECTION/END-TEST-INJECTION を使用します。新しいコードではコンストラクター注入を優先してください。
上記すべての完全なコード例については、references/test-environment-examples.md を参照してください。
ベストプラクティス
テスト設計
- テストごとにアサーションの概念は 1 つ — 各テストでは 1 つの振る舞いを検証してください
- 説明的なテストメソッド名 —
test_1ではなくtest_reject_negative_quantityを使用してください - 独立したテスト — あるテストの結果や実行順序に依存するテストがあってはなりません
- 高速なテスト —
DURATION SHORTを使用し、不要なセットアップを避けてください
テストの分離
- 外部依存関係(DB、API、その他の BO)には必ずテストダブルを使用します
- クリーンな状態を保つために、
setup/teardownを使用します - 高コストな一度限りのセットアップ(テスト環境)には、
class_setup/class_teardownを使用します - テスト環境クラスの
setupでは、必ずclear_doubles( )を呼び出します class_teardownでは、必ずdestroy( )を呼び出します
テストの構成
- テストクラスはローカルテストインクルード(ADT のテストクラスのタブ)に配置します
- テストダブルの名前には
ltd_(ローカルテストダブル)を接頭辞として付けます - テストクラスの名前には
ltc_(ローカルテストクラス)を接頭辞として付けます - 関連するテストは同じテストクラスにまとめます
テスト対象
- ビジネスロジックと計算
- 検証ルールとエラーケース
- エッジケース(空の入力、境界値、null 参照)
- CDS ビューの計算と集計
- RAP ハンドラーのロジック(アクション、検証、判定)
テスト対象外
- フレームワークが提供する機能(RAP のマネージド CRUD)
- 単純な getter/setter メソッド
- ABAP ランタイムの動作
参考資料
- SAP ABAP チートシート — ABAP 単体テスト
- SAP ヘルプ — ABAP Unit
- SAP ヘルプ — CDS テストダブルフレームワーク
- SAP ヘルプ — RAP BO テストダブル
- Clean ABAP — テスト
関連スキル
- cds-view-entities:CDS テスト環境を使用した CDS ビューエンティティのテストに使用します
- rap:RAP テストダブルを使用した RAP ビジネスオブジェクトのテストに使用します
- clean-abap:テストコードが Clean ABAP の原則に従っていることを確認するために使用します