【ABAP】ABAP Unitを使ってみよう(4)　～CDS：セッション変数をTest Doubleにしようとして失敗した話

##はじめに
この記事は、「ABAP Unitを使ってみよう」シリーズの4回目です。
過去の記事はこちら↓
[【ABAP】ABAP Unitを使ってみよう(1)　～簡単なところから](https://qiita.com/tami/items/374c315ff88249db1b7d)
[【ABAP】ABAP Unitを使ってみよう(2)　～Test Doubleで依存性を解決する](https://qiita.com/tami/items/117952bfe22ec2ba0e0f)
[【ABAP】ABAP Unitを使ってみよう(3)　～CDSビューのテスト](https://qiita.com/tami/items/4fa6994f0cb4ce336a92)

##CDS Test Double Frameworkでセッション変数をコントロールできるのか？
CDSビューで、パラメータやwhere句にセッション変数（ログオンユーザ、言語など）を指定している場合があります。Unitテストでは、実行環境やユーザによって結果が変わってほしくないので、セッション変数をコントロールしたいです。
[ヘルプ](https://help.sap.com/viewer/5371047f1273405bb46725a417f95433/Cloud/en-US/cbedc08ff4de48ffa8d04d3067ef08e7.html)には、CDS Test Double Framework(TDF)でセッション変数のTest Doubleを作れると書いてあったのですが、**結局のところやり方がわかりませんでした。**

今回の記事では、以下について書きたいと思います。
1. できなかったこと
2. 代替案

###1. できなかったこと
####テスト対象のビュー
登録ユーザ(CREATED_BY)が、セッション変数のユーザ（実行ユーザ）であるレコードを取得するCDSビューです。

```abap
define view ZMOB49_I_PRICE
as select from zprice 
{
    //zprice 
    key material, 
    text, 
    price, 
    currency, 
    created_by
}where created_by = $session.user
```

####テストクラス
[前回](https://qiita.com/tami/items/4fa6994f0cb4ce336a92)と同様の手順でテストクラスを作成しました。
そもそも、セッション変数（$session.user）をTest Doubleに置き換える方法がわからなかったので、苦肉の策でsy-unameを書き換えてみました。

```abap
    " change user
    sy-uname = 'TESTUSER'.

    SELECT * FROM zmob49_i_price INTO TABLE @act_results.
    describe table act_results lines data(lv_cnt).
```

全体のコード

```abap
CLASS ltc_zmob49_i_price IMPLEMENTATION.

  METHOD class_setup.
    environment = cl_cds_test_environment=>create( i_for_entity = 'ZMOB49_I_PRICE'
      test_associations = 'X'  ).


  ENDMETHOD.

  METHOD setup.
    environment->clear_doubles( ).
  ENDMETHOD.

  METHOD class_teardown.
    environment->destroy( ).
  ENDMETHOD.

  METHOD get_data.
    prepare_testdata_set( ).

    " change user
    sy-uname = 'TESTUSER'.

    SELECT * FROM zmob49_i_price INTO TABLE @act_results.
    describe table act_results lines data(lv_cnt).


    cl_abap_unit_assert=>assert_equals(
      EXPORTING
        act                  = lv_cnt
        exp                  = 1
        msg                  = 'No record found for TESTUSER'
        quit                 = if_aunit_constants=>quit-test
    ).
  ENDMETHOD.

  METHOD prepare_testdata_set.

    "Prepare test data for 'zprice'
    lt_zprice = VALUE #(
      (
        mandt = sy-mandt
        material = 'M-001'
        text = 'TEST'
        created_by = 'TESTUSER'
      ) ).
    environment->insert_test_data( i_data =  lt_zprice ).

  ENDMETHOD.
```
結果はNGでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/c7ae3ed1-1a97-d69d-5daa-fe2de6b4749f.png)

テストデータ作成時に、登録ユーザを自分のユーザに変えたら成功したので、やはり上記の方法ではセッション変数を書き換えることはできないということです。

```abap
    lt_zprice = VALUE #(
      (
        mandt = sy-mandt
        material = 'M-001'
        text = 'TEST'
        created_by = '自分のユーザ'
      ) ).
```

###2. 代替案
####①パラメータでユーザを指定する
CDSビューのwhere句でセッション変数を指定するのではなく、パラメータに対象のユーザを渡す方式にします。

```abap
define view ZMOB49_I_PRICE
with parameters
  @Environment.systemField: #USER 
  P_user: syst_uname
as select from zprice 
{
    //zprice 
    key material, 
    text, 
    price, 
    currency, 
    created_by
}where created_by = $parameters.P_user
```

アノテーション`@Environment.systemField: #USER `をつけると、パラメータが指定されない場合は実行ユーザが設定されます。

#####テストクラス
CDSビューからレコードを取得するときに、パラメータに任意のユーザを指定します。

```abap
    SELECT * FROM zmob49_i_price( p_user = 'TESTUSER' ) INTO TABLE @act_results.
    describe table act_results lines data(lv_cnt).
```

結果、テストはOKになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/28368dc8-b154-eda6-a211-cf4438fbb7a5.png)

####②テストデータを登録するときに、登録者にSY-UNAMEを指定する
こちらは実機で試していませんが、うまくいくはずです。
ただ、感覚的には外部からコントロールできるパラメータで指定する①のほうがいい作りのような気がします。

```abap
    lt_zprice = VALUE #(
      (
        mandt = sy-mandt
        material = 'M-001'
        text = 'TEST'
        created_by = sy-uname
      ) ).
```


##調べる過程で見つけたもの
以下のパッケージに、Test Doubleを使ったサンプルのテストクラスが入っています。

- SABAP_UNIT_DOUBLE_CDS_DEMO：CDS Test Double Frameworkのデモ
- SABAP_UNIT_DOUBLE_OSQL_DEMO：ABAP SQL Test Double Frameworkのデモ