mcpField
A
abap-unit-testing

abap-unit-testing

github.com/likweitanテスト・品質7299 回インストール2 週間前に更新
リポジトリ

abap-unit-testing について

abap-unit-testingは、ABAP Unitテストの作成ガイドとなるスキルです。業務ロジック、CDS、SQL依存コード、RAPのテスト方法に加え、アサーションやテストダブル、テスト環境を解説します。

主な機能

  1. 01ABAP Unitテストクラスの構成
  2. 02アサーションとAAAパターン
  3. 03依存性注入とテストダブル
  4. 04CDSとOSQLのテスト環境
  5. 05RAP BOテストダブル

活用シーン

  1. 01業務ロジックと検証ルールのテスト
  2. 02データベース依存コードのスタブ化
  3. 03CDSビュー計算のテスト
  4. 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 テストの作成ガイドです。

ワークフロー

  1. テストの目的を特定します:

    • クラスメソッドのビジネスロジックをテストする
    • CDS ビューエンティティをテストする
    • RAP BO の振る舞いの実装をテストする
    • SQL テストダブルを使ってデータベース依存のロジックをテストする
    • 外部依存関係のテストダブルを設定する
  2. 適切なアプローチを選択します:

    • 純粋なロジック(依存関係なし)には直接ユニットテストを使用する
    • モック可能な依存関係にはコンストラクター/セッターインジェクションを使用する
    • CDS ビューのテストには CDS テスト環境を使用する
    • SQL 依存コードには OSQL テスト環境を使用する
    • RAP の振る舞いのテストには RAP BO テストダブルを使用する
  3. AAA パターンに従います:準備 → 実行 → 検証

  4. テストを独立させます:テストが永続データや外部システムに依存しないようにします

テストクラスの基本

テストクラスの定義
"! 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.
テストクラスの属性
属性オプション目的
DURATIONSHORT / MEDIUM / LONG想定される実行時間。SHORT は 1 秒未満(CI のデフォルト)
RISK LEVELHARMLESS / 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_codesy-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 ランタイムの動作

参考資料

関連スキル

  • cds-view-entities:CDS テスト環境を使用した CDS ビューエンティティのテストに使用します
  • rap:RAP テストダブルを使用した RAP ビジネスオブジェクトのテストに使用します
  • clean-abap:テストコードが Clean ABAP の原則に従っていることを確認するために使用します

コメント