メニューボタン
IBMi海外記事2021.05.26

スタブを使用したテストとSQL

Ted Holt 著

スタブプログラムは、特段何の機能も持たないが本当のプログラムのプレースホルダ―としておかれるプログラムのことを言います。この本当のプログラムが実際に存在する場合もあれば、存在しないこともあります。私は、プログラムの変更をテストするため、長年にわたってこれを使用してきました。スタブサブルーチンやスタブサブプロシージャなどもあります。今回は、同様の概念をSQLクエリに応用する方法について説明したいと思います。

スタブの勉強には好みの検索エンジンを使用してかまいませんが、まず私が何の話をしているかを理解していただくため、例を挙げましょう。例えば、私はいまRPGプログラムを呼び出すCLプログラムを修正しようとしているとします。このCLプログラムには大量の条件論理が含まれていて慎重なテストを要しますが、RPGプログラムには修正を加える必要はありません。

. . . some code
call rpgpgm1  parm(&Cancel)
if cond(&Cancel *ne '1') do
   call rpgpgm2  parm(&SomeDate &SomeNumber &Status)
   select
      when (&Status *eq 'A') do
         . . . whatever
      enddo
      when (&Status *eq 'F') do
. . . more code
. . . etc.
. . . and so forth

ここでちょっとしたCLプログラムを書いて、それにPRGPGM1という名前を付けます。

pgm  parm(&Status)
dcl  &Status   *char  1
chgvar  &Status  '0'
endpgm

本当のRPGPGM1が実際にRPGで書かれているかどうかは問題ではありません。また、本当のPRGプログラムに何が入力されるかも重要ではありません。この短いCLプログラムは、私が検証をするために必要なことをしてくれるのです。

もちろん、RPGPGM1の呼び出しをコメントアウトして、一時的にCHGVARコマンドを追加し、&CANCELの値をゼロにすることもできますが、そうなると本番で使用されるCLコードと違うものになってしまうでしょう。

私が使う中でも一番短いスタブプログラムはこちらです。非常によく使います。

pgm
endpgm

私はこのソースメンバーを、テストライブラリにコンパイルし、プログラムのオブジェクトが持っていなければならない名前を付けます。

スタブプログラムは、フローとロジックを検証する際には非常に便利です。次にSQLについて考えてみましょう。同じようなことをできるでしょうか。つまり、検証とは全く関係のないデータにアクセスすることなく、クエリの一部分のみを検証することはできるでしょうか。答えは、イエスです。

多くのショップでは、テストは本番用データ、あるいは本番用データのコピーを使って行われます。これが良いやり方かそうでないかは重要ではありません。実際に行われているというだけです。そのようなデータを使用して行われるテストは多くの場合、信頼度が低いか、非常に難しいものです。これには主に2つの理由があります。

  • データが多すぎる(結果セットの行が多すぎる)
  • データがすべての論理条件を実行するために必要な値をすべて含んでいない

これらの阻害要因は、必要なテーブルとビュー(物理ファイルと論理ファイル)をテストライブラリに作成し、必要なデータのみのテーブルをロードすることで解決できます。それも良いアプローチではありますが、時間がかかります。例えば、ビューの一つがテーブルのビューのビューだったらどうでしょうか。セットアップするだけでもかなりの時間がかかってしまいます。

同じ目的を達成するための別の方法があります。こちらの方がずっと簡単です。

以下に例をお見せします。顧客情報を取得する非常に洗練されたクエリです。

select c.CusNum, c.LstNam,                    
       c.City, c.State,
       c.ZIPCod               
  from qcustcdt as c                          
 order by c.CusNum;
192837 Lee Hector NY 14841
389572 Stevens Denver CO 80226
392859 Vine Broton VT 5046
397267 Tyron Hector NY 14841
475938 Doe Sutter CA 95685
583990 Abraham Isle MN 56342
593029 Williams Dallas TX 75218
693829 Thomas Casper WY 82609
839283 Jones Clay NY 13041
846283 Alison Isle MN 56342
938472 Henning Dallas TX 75217
938485 Johnson Helen GA 30545

例えば、このクエリによる出力データを利用する人が、2文字の略称ではなく州の名称を出力したいと考えたとしましょう。そこで「STATES(州)」というテーブルを追加しました。

select c.CusNum, c.LstNam,                    
       c.City, coalesce(s.Name,c.State) as State,
       c.ZIPCod               
  from qcustcdt as c                          
  left join states as s
    on c.State = s.Abbreviation
 order by c.CusNum;

変更を確認するため、クエリを実行してみます。すると、このようになりました。

192837 Lee Hector New York 14841
389572 Stevens Denver Colorado 80226
392859 Vine Broton Vermont 5046
397267 Tyron Hector New York 14841
475938 Doe Sutter California 95685
583990 Abraham Isle Minnesota 56342
593029 Williams Dallas Texas 75218
693829 Thomas Casper Wyoming 82609
839283 Jones Clay New York 13041
846283 Alison Isle Minnesota 56342
938472 Henning Dallas Texas 75217
938485 Johnson Helen Georgia 30545

一見うまくいったように見えますが、QCUSTCDTの州名はSTATESテーブルにあるので、COALESCE関数が想定通りに機能したかは確認することができません。これを検証する方法は2つ考えられます。

  • QCUSTCDTの検証用コピーに無効な州コードを含んだ行を追加する
  • STATESテーブルから1つ以上の州を削除する

しかし、もっと簡単な方法があります。それは、スタブを使ってSTATESテーブルに代入する方法です。次のようにします。

select c.CusNum, c.LstNam,                    
       c.City, coalesce(s.Name,c.State) as State,
       c.ZIPCod               
  from qcustcdt as c                          
--  left join states as s
    left join (values ('TX', 'Texas')) as s (Abbreviation, Name)
    on c.State = s.Abbreviation
 order by c.CusNum;

STATESテーブルへの参照をコメントアウトし、代わりに1行の代入データを行値式として定義しました。

--  left join states as s
    left join (values ('TX', 'Texas')) as s (Abbreviation, Name)

この行値式には、同じカラム(フィールド)名が与えられています。ABBREVIATION とNAMEです。STATESテーブルには他のカラム(フィールド)があるということは問題ではありません。ここでは、この行値式に同じ相関名である「S」一文字を割り当てました。

この代入テーブルでは1行だけしか定義していないので、テキサスの場合には州名が入り、その他の州の場合には州コードが入るはずです。ではやってみましょう。

192837 Lee Hector NY 14841
389572 Stevens Denver CO 80226
392859 Vine Broton VT 5046
397267 Tyron Hector NY 14841
475938 Doe Sutter CA 95685
583990 Abraham Isle MN 56342
593029 Williams Dallas Texas 75218
693829 Thomas Casper WY 82609
839283 Jones Clay NY 13041
846283 Alison Isle MN 56342
938472 Henning Dallas Texas 75217
938485 Johnson Helen GA 30545

これで、COALESCE関数が思った通りの動作をしてくれたことを確認できました。スタブを外してSTATESテーブルを接続しても大丈夫です。

行値式を使用することによって、本番で実行されるコードと違うものを実行しているのではないか、と反論することもできるでしょう。私はそれを否定はしません。ただ、高いレベルの抽象化を行うことで、データがどこから得られたものかということを考えずに、どのような形で出力されるかにのみ集中できるということなのです。

今回、スタブには1行だけしか必要なかったので1行だけ使用しましたが、必要に応じて2行以上にすることもできます。例えば、以下の通りです。

left join (values ('TX', 'Texas'),
                  ('CO', 'Colorado')) as s (Abbreviation, Name)

行値式を追加して、それぞれをカンマで区切っていくだけです。

時には本番環境に十分な検証をしていないソフトをインストールしてしまう人もいるかと思います。それは、もしかすると、十分なテストを設定するのがあまりにも難しいという理由からかもしれません。そんな時は今回紹介したツールが役に立つことでしょう。

あわせて読みたい記事

PAGE TOP