##はじめに
この記事は、「ABAP Unitを使ってみよう」シリーズの2回目です。
1回目の記事はこちら↓
【ABAP】ABAP Unitを使ってみよう(1) ~簡単なところから
##自動テストにおける依存性の問題
自動テストでは、テスト対象のソースコードが変わらない限り、実行の都度同じ結果が得られることが求められます。このためには実行環境(たとえば、DBに入っているデータ)によってテストが影響を受けないようにする必要があります。
テスト対象のコードが依存する他のコードやDBなどをdepended-on component(DOC)と呼び、テストではDOCが毎回同じ動きをするようにコントロールする必要があります。
Managing Dependencies with ABAP Unitより引用
##Test Double
Test Doubleとは、テストのときだけDOCに代わって動くコードです。本番用のコードだとDOCが返す結果が変わってしまう場合に、Test Doubleを用意します。あくまでもテスト対象のコードは本番と同じコードであり、テスト対象の外部にあるコードを置き換える、というところがポイントです。
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を作成します。テストの要領は以下の通りです。
- テストクラスの初期処理で、使用するテーブルを宣言してTest Doubleを生成する
- 各テストの前にテストデータをクリアする(毎回同じ結果になるように)
- テストデータを挿入する(本物のDBではなく、Test Doubleに)
- テストが終わったらTest Doubleも終了する
###テストシナリオ
キーを指定してテーブルZPRICEを読み込むメソッドを作成します。テストでは、データが正しく取得できていることを確認します。
###テストコード
テストは前回の記事と同じテストクラスに書いています。
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.
実行結果
最初はテスト対象のメソッドが空の状態で実施します。結果は以下の通りエラーになります。ここで気づいたのですが、テストの実施順はメソッドの定義順ではなく、メソッドのアルファベット順になるようです。
###テスト対象のメソッド実装
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を付けました)
##感想
DBがからむテストは、通常はテストデータを手で登録したり、トランザクションを使って登録したりと結構手間だったりします(テストパターンが多いとさらに大変)。Test Doubleを使うと欲しいデータをすぐに用意できるメリットがあると感じました。