ソフトウェアの品質を学びまくる2.0

ソフトウェアの品質、テストなどについて学んだことを記録するブログです。

モデルベースドテストについて学んでみよう - その2

Melissa Adret, Model

 モデルベースドテスト(Model-based Testing、MBT)について学ぶシリーズの第2回です。2018年アドベントカレンダーの2日目でもあります。

www.kzsuzuki.com

 第1回を振り返ってMBTとさくっと説明すると、「要求・仕様に基づいてモデルを描き、そこからテストケースを生成する」というものでした。ISTQBのシラバスを読みながらMBTを理解していくことを考えていましたが、やっぱりツールを使ってみます。

 今回使うのは、「MISTA」というツール。
 クイックガイドに掲載されているモデルを作成してみましょう。

MISTAとは

 Model-based Integration and System Testing Automation の略で、モデルベースのテスト生成ツールです。
 アーカイブはBoise州立大学で配布していたのですが、そのサイトが消えている・・・。もしかするともう公開されていないのかもしれません。

 MISTAの特徴は以下の通りです。

  • 描いたモデルに対し、シミュレーションを行うことができる。
  • モデルから、複数のカバレッジ基準に合わせて、テストケースを自動生成できる。
  • モデルなどの情報から、目的の言語に合わせて実行可能なテストコードを生成し、テスト対象システムで実行することができる。
  • モデルとして、function net、UML protocol state machine、contractsという3つがサポートされている。

 モデルなど、と書きましたが、具体的には以下の3つです。

  1. MISTAで描いたモデルそのもの
  2. モデルと実装を関連付けるMIM(model-inplementation mapping)
  3. プログラミング言語ごとに必要な補助コード

 モデル作成とテストケース生成は1.だけでもできますので、この記事ではそれをやってみましょう。

MISTAでファンクションネットを描いてみる

 上述の通り、MISTAは3つのモデルをサポートしています。5つのものから選ぶのはいい! 3つのものから選ぶのもいい! だが「4つ」のものから選ぶとよくない事が起こるんだ。

 今回は、function net(以降、「ファンクションネット」を使ってみましょう。
 なぜなら、MISTAのデフォルトがファンクションネットですし、もっというとcontractsって何かわからないからです。契約プログラミングの文脈なのでしょうか・・・?

 そうはいっても、ファンクションネットが何かを知らない方もいるでしょう(わたしです)。
 ですので、MISTAでモデルを実装しながら、雰囲気をつかんでいくことにしましょう。わたしも同じ流れで理解しているだけなので、嘘・不正確があったらごめんなさい。

実装する仕様

 ガイドでは、ブロックゲームを例にしています。
 ブロックゲームの概要はこんな感じ。

  • テーブルの上に、複数のブロックが乗っている。
    • テーブルの上に直接乗っているものもあれば、他のブロックの上に乗っているものもある。
  • アームを使ってブロックをつかむことができる。
    • 一度につかめるブロックは一つだけ。
    • 他のブロックの下にあるブロックはつかめない。
  • アームでつかんだブロックは、テーブルの上か、他のブロックに乗せることができる。
  • 初期の配置(INIT)から、指定された配置(GOAL)にもっていくことが目的。

 この仕様から導出される操作は、以下の4つです。

  • pickup(x): ブロックxをテーブルから上げる
  • putdown(x): ブロックxをテーブルに下ろす
  • stack(x, y): ブロックxをブロックyに上に下ろす
  • unstack(x, y): ブロックxをブロックyの上から上げる

 また、ブロックの状態は、以下の4つです。

  • ontable: テーブルの上にある
  • holding: アームがブロックをつかんでいる
  • on: 他のブロックの上にある
  • clear: 他のブロックの下にない

 ものすごくめんどくさかったのですが、がんばって絵を描いてみました。

f:id:kz_suzuki:20200426185237p:plain

 状態遷移図に慣れた人は違和感をもったかもしれません。ブロックの状態同士がMECEではないのでは?と。たとえば、onclearは両立しますよね。
 実はファンクションネットにおいては、これらを「状態」と呼ぶのは適切ではないのですが、説明は後ほどとして、暫定的に「状態」と呼んでおきます。

とりあえず描き始めてみる

 まず、ontableholdingという2つのブロック状態のノードを置いてみましょう。
 ファンクションネットではこのノードのことを、Placeと呼んでいます。この記事では「プレース」と呼ぶことにしましょう。

f:id:kz_suzuki:20200426185241p:plain

 状態遷移図だと、状態と状態の間の矢印が遷移を表しています。
 一方、ファンクションネットにおいては、あるプレースから別のプレースへの遷移の間にイベントのノードを置き、プレースからイベントへ、イベントからプレースへ矢印が引かれます。MISTAではこのノードのことを Transision と呼んでいるのでちょっとややこしいのですが、この記事では以下のように呼びます。

  • トランジション: プレースからプレースへの移動
  • イベント: トランジションを起こす契機となる事象

 テーブルの上にあるブロックをアームで持ち上げて、その後にまたテーブルに下ろすモデルを描いてみましょう。この2つの四角が、イベントです。

f:id:kz_suzuki:20200426185245p:plain

 とりあえず、遷移の輪が閉じました。

変数と初期状態を追加する

 ここでモデル検証のため遷移のシミュレーションをしたいのですが、追加しなくてはならない情報がまだいくつかあります。

 pickup(x)では、テーブルの上にある1個以上のブロックの中から、特定のブロックxを選んで持ち上げることになります。
 ですので、プレースontableからの矢印に「x」というラベルを付けます。プレースholdingに遷移するのも同じブロックですから、そちらの矢印にも「x」を付けます。変数xを受け渡すことで、「持ち上げたブロックと、アームがもっているブロックが同一である」ことを意味しているわけです。

 同じように、putdown(x)に入る矢印、出る矢印にも「x」というラベルを付けます。
 なお、変数のスコープは分かれており、上の遷移のxと下のxは別モノとして扱われます。   f:id:kz_suzuki:20200426185248p:plain

 次に初期状態を指定します。
 モデルの中に Annotation(アノテーション)というものを置き、その中に記述することになります。
 ここでは、2つのブロック「B1」「B2」が、ともにテーブルの上にある(積まれていない)としましょう。
 以下のような記述になります。

INIT ontable(B1), ontable(B2)

f:id:kz_suzuki:20200426185252p:plain

 これでシミュレーションの準備ができました。

モデルのシミュレーション

 シミュレーションを実行してみましょう。実行画面はこんな感じ。
 Simulation Contorol Panel というウィンドウが表示され、モデルも色づいています。

f:id:kz_suzuki:20200426185256p:plain

 モデルの方から見てみましょう。
 プレースの中に、何やら青い点が出現していますね。これを「トークン」と呼びます。ブロックを2つ定義していますので、トークンも(最低)2つあります。初期状態はともにontableとしましたが、それを表現しているのがこのトークンなのです。

 個々のブロックに対応するトークンがその瞬間、どのプレースに配置されているか。実はこれこそが、システムの「状態」と呼ぶべきものです。各ブロックの状態もトークンの配置の組み合わせで表現されるため、プレースは排他である必要がありません。

 赤く塗られたイベントは、この状態で実行可能なイベントです。2つのブロックがともにテーブルの上にある状態なので、アームはどちらかを持ち上げることができます。

 次に、パネルを見てみます。
 左ペインの真ん中に、現在の状態(トークンの配置)が書かれています。
 右ペインのEventフィールドでは、実行可能なイベントが選べます。ここではpickup(x)のみです。Parametersフィールドでは、xに対する値を指定します。ここではB1B2を選ぶことになります。

 ではこの初期状態から、イベントにpickup(x)、パラメタxB1を選んで、Playをクリックしてみましょう。

f:id:kz_suzuki:20200426185300p:plain

 モデル上でトークンが1つ、プレースholdingに遷移していることがわかります。アームにブロックB1がつかまれている状態です。
 この状態では、イベントpickup(x)だけでなくputdown(x)も赤くなっており、実行可能であることがわかります。アームでつかんだブロックB1を下ろせるということです。

 パネルの左を見ると、状態は「B2はテーブル上にあり、B1はアームにつかまれている」ことがわかります。
 また右を見ると、イベントとしてpickup(x)putdown(x)が選択できます。指定できるパラメタはそれぞれ、B2B1です。

 このように、描いたモデルに対しシミュレーションを実行して、想定外の動きにならないか、指定した状態に到達可能か、といった検証を行うことができます。

 次回はこのモデルの問題点を直し、完成させていきましょう。

www.kzsuzuki.com