4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【ABAP】ABAP Unitを使ってみよう(2) ~Test Doubleで依存性を解決する

Posted at

##はじめに
この記事は、「ABAP Unitを使ってみよう」シリーズの2回目です。
1回目の記事はこちら↓
【ABAP】ABAP Unitを使ってみよう(1) ~簡単なところから

##自動テストにおける依存性の問題
自動テストでは、テスト対象のソースコードが変わらない限り、実行の都度同じ結果が得られることが求められます。このためには実行環境(たとえば、DBに入っているデータ)によってテストが影響を受けないようにする必要があります。
テスト対象のコードが依存する他のコードやDBなどをdepended-on component(DOC)と呼び、テストではDOCが毎回同じ動きをするようにコントロールする必要があります。
image.png
Managing Dependencies with ABAP Unitより引用

##Test Double
Test Doubleとは、テストのときだけDOCに代わって動くコードです。本番用のコードだとDOCが返す結果が変わってしまう場合に、Test Doubleを用意します。あくまでもテスト対象のコードは本番と同じコードであり、テスト対象の外部にあるコードを置き換える、というところがポイントです。

image.png
Managing Dependencies with ABAP Unitより引用

##Test Doubleの種類
Test Doubleを作成するためにTest Double Frameworkというものが用意されており、以下の種類があります。

DOCの種類 Test Double
クラス ①Test Doubleクラスをマニュアルで作る
②ABAP Test Double Framework
データベース(CDS) CDS Test Double Framework
データベース(SQL) ABAP SQL Test Double Framework
その他(ソースコード) ABAP Test Seams

##【今回のテーマ】ABAP SQL Test Double Framework
今回の記事では、ABAP SQL Test Double Frameworkを使ってDBへのアクセスをTest Doubleに置き換えてみます。

###概要
IF_OSQL_TEST_ENVIRONMENTというインターフェースがTest Doubleを作成します。テストの要領は以下の通りです。

  1. テストクラスの初期処理で、使用するテーブルを宣言してTest Doubleを生成する
  2. 各テストの前にテストデータをクリアする(毎回同じ結果になるように)
  3. テストデータを挿入する(本物のDBではなく、Test Doubleに)
  4. テストが終わったらTest Doubleも終了する

###テストシナリオ
キーを指定してテーブルZPRICEを読み込むメソッドを作成します。テストでは、データが正しく取得できていることを確認します。

ZPRICE
image.png

###テストコード
テストは前回の記事と同じテストクラスに書いています。

クラス定義
赤枠の変数、およびメソッドを追加しました。
image.png

class_setup
このメソッドはテストクラス実行時、最初に1回だけ呼ばれます。

  METHOD class_setup.

    "使用するテーブルを指定してTest Doubleを生成
    environment = cl_osql_test_environment=>create(
      i_dependency_list = VALUE #( ( 'ZPRICE' ) )
    ).

  ENDMETHOD.

setup
このメソッドは、各テストメソッドが実行される前に呼ばれます。

  METHOD setup.
    ...

    "各テスト実行前にTest Doubleをリフレッシュする
    environment->clear_doubles( ).

  ENDMETHOD.

class_teardown
このメソッドは、テストクラスの終了前に呼ばれます。

  METHOD class_teardown.
    "Test Doubleを終了する
    environment->destroy( ).
  ENDMETHOD.

get_price
テーブルZPRICEを読み込むメソッドのテストです。

  METHOD get_price.
    data: lt_price type standard table of zprice,
          ls_price type zprice,
          ls_price_exp type zprice,
          lv_material type matnr.

    " テストデータを挿入
    ls_price_exp = value #( MATERIAL = 'MAT-001' TEXT = 'Test' PRICE = '100.00' CURRENCY = 'USD' ).
    append ls_price_exp to lt_price.
    environment->insert_test_data( lt_price ).

    " テスト対象のメソッドを実行
    lv_material = 'MAT-001'.
    ls_price = mo_class_under_test->get_price( iv_material = lv_material ).

    cl_abap_unit_assert=>assert_equals(
      EXPORTING
        act                  = ls_price             " 実際の結果
        exp                  = ls_price_exp         " 想定結果
        msg                  = 'get price function not working' " エラーの場合のメッセージ
        quit                 = if_aunit_constants=>quit-test
    ).

  ENDMETHOD.

実行結果
最初はテスト対象のメソッドが空の状態で実施します。結果は以下の通りエラーになります。ここで気づいたのですが、テストの実施順はメソッドの定義順ではなく、メソッドのアルファベット順になるようです。
image.png

###テスト対象のメソッド実装

  METHOD get_price.

    SELECT SINGLE material, text, price, currency
    FROM zprice
    WHERE material = @iv_material
    INTO CORRESPONDING FIELDS OF @r_result.

  ENDMETHOD.

###テスト結果
正常終了になりました。(say_helloのテストを最初に実行するように、メソッド名の先頭にprifixを付けました)
image.png

##感想
DBがからむテストは、通常はテストデータを手で登録したり、トランザクションを使って登録したりと結構手間だったりします(テストパターンが多いとさらに大変)。Test Doubleを使うと欲しいデータをすぐに用意できるメリットがあると感じました。

4
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?