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

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

モデルベースドテストについて学んでみよう - その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