モデルベーステスティング回想|テスト技法


こんにちは。株式会社SHIFT、自動化エンジニアの水谷です。

最近ふとしたきっかけで「モデルベーステスティング」というテスト技法について振り返る機会がありましたので、今回はこれについて思い出しながら少し書いてみたいと思います。このテスト方法はどのようなものなのでしょうか? そして我々テストエンジニアが積極的に関わって(使って)いくべきものでしょうか?

モデルベーステスティングとは

ウィキペディアでモデルベーステスティングのページを見ると、このように書かれています。

モデルベーステスト(Model-based testing)とは、テストケースの一部または全部を評価対象システムの(通常、機能的側面を)モデル化したものから導出して行うソフトウェアテストの手法である。

Wikipediaより

そこそこわかりやすい文章ですが、より短く書くと、「ソフトウェアの”モデル”からテストケースを導出する手法」、ということになります。つまり、モデルベーステスティングは、あくまでテストケースを作り出す方法の1つであり、(一般的には)テストケースの導出のみに限定され、テストの設計方法や実行方法などは含まないものということになります。

図1
画像:筆者作成

さて、モデルベーステスティングがテストケースを作成する手法の1つだとわかりましたが、ここには重要なポイントが1つ隠れています。

モデルからテストケースを生成すると言っても、それを手動で行うなら、これは部分的にせよ普段のテストケース作成で行っている作業ですよね。しかし、特に大きなプロジェクトで複雑なモデルからテストケースを作ること考えると、おそらくとても時間がかかり、抜け漏れも出やすいだろうなぁ、と容易に想像がつきますね。

そこで、モデルベーステスティングは、このモデルからテストケースの導出をツールで自動化することで、短時間で抜け漏れの無いテストケースを作成しようというものなのです。

モデルベーステスティングのツール

モデルベーステスティングは、テスト手法の1つであり、これを達成するためのツールが複数作成されました。その中でも有名なものの1つがMicrosoftで作られた「Spec Explorer」でして、私も10年ほど前にこれを使った経験があります。

Spec Explorerは、「Spec#」と呼ばれるC#を拡張した言語を使って、状態遷移図に相当するモデルを記述します。そして、これをビルドすると下の例のようにビジュアル化された状態遷移図とテストケースがズラズラッと生成されるのです! 素晴らしい。

図2

SpecExplorerが出力した状態遷移図の例(Microsoftのページhttps://docs.microsoft.com/ja-jp/previous-versions/visualstudio/spec-explorer/ee620464(v=specexplorer.10) より引用)

でも、これ普及してないよね?

ほんと素晴らしいのですが、このツールこの10年ほどアップデートもされていないし、思ったほど普及もしていません。もしこれがほんとにうまく働くのなら世界のテスターはとても仕事が楽になるはずなのですが、現実的にはほとんど使われていません。なぜでしょうか? 実はこの手法およびこのツールは、思ったほどはうまく機能しないことが多いのです。正確には、この手法やツールがうまく動作するプロジェクトもあるのですが、うまくいかないプロジェクトが多いのです。

Spec#はどんなものだったのか

と、かなりネガティブに書いてしまいましたが、上手くいかないと知ったとしてもSpecExplorerがどんなもので、Spec#がどんな言語だったのかを知っておくのは良いことだと思います。
先ほども書きましたように、Spec#はC#の拡張言語です。どのような拡張がされているか、というと、大きく3点あります。

1. null非許容型を追加して、引数のチェックを可能にする
2. その状態になるための条件を明確に記述できる
3. その状態から離脱するときの状態チェック(テスト)をコードで記述できる

1.は置いておいて、2.と3.に注目します。Spec#では、各状態はそれぞれ1つのメソッドとして記述するのですが、このときにこれら2つを記述します。例えば、ある状態(stateA)に遷移するためにはint型のグローバル変数(状態変数)のgValueが2以上であることが必要条件であり、その状態から離脱するときにはgValueが3になるはずである、という場合は、以下のように記述します。

class Example {
   int gValue;
   void stateA(int x, int y)
       requires gValue >= 2;
       ensures gValue == 3;
   {
       …
   }
   …
}

このメソッド内書かれているrequiresが2.にあたり、ensuresの行が3.にあたります。もちろん、requiresやensuresは複数記述することができ、ここを正しく記述することがポイントになります。そして、これをすべての取りうる状態について(メソッドとして)記述していくのです。

記述が終わり、SpecExplorerでビルドをすると、“すべての状態遷移パターンを網羅する”遷移経路リストが作成されます。そして、これはグラフィカルにも表示できました。このグラフィカルな表示を見るのは楽しく、遷移経路1は初期状態からこんな順で遷移して、最終状態がここになり、遷移経路2は初期状態からこんな順で遷移して、この最終状態にたどり着くのだな、と目でたどって行け、しかもこんな遷移パターンもあるのかと気づかされてたりします。ビジュアライズされるだけでも得るものがあるのですが、なにより良いのが完全に網羅する遷移経路リストが得られることです。なぜなら、これは網羅率(カバー率)100%のテストケースとなるからです。

また、Spec#には各状態から次の状態(複数ある場合もあります)に遷移するための操作を自動化するコードも合わせて記述することができます(具体的な記述方法やルールは失念しました……)。こうしておくと、SpecExplorerは各遷移経路について、自動的に状態遷移しつつ、requiresやensuresで記述した条件が満たされているかのチェックするコードを生成してくれます。そして、それを実行することですべての遷移経路を自動的にテストすることが可能となるのです。

実際に使ってみた(10年前に)

実際私はSpecExplorerおよびSpec#を試したいと思い、当時関わっていた製品のインストーラーのテストを自動化してみた経験があります。

インストーラーは一般的なウィザード形式のもので、トップ画面から「次へ」ボタンを押すと使用許諾が表示され、合意の意思を示すチェックボックスがあり、チェックすると「次へ」ボタンが押せ、次はインストール先フォルダを指定でき、「次へ」ボタンを押すとファイルのコピーが始まり、インストールが終わると「完了」ボタンが表示され、これを押すとインストーラーが終了する、というものでした。

非常に簡単なので、状態数は10程度、UIも簡単だし状態変数の数も数個程度です。これをSpec#で記述し、UIAutomationライブラリで状態遷移(「次へ」ボタンを自動的に押すなど)を記述して、SpecExplorerで処理すると、記憶が正しければ10程度の遷移経路と、それをたどっていきながらテストを行うコードが生成されました。合計の遷移数はたしか60程度です。実行してみると、3~4分程度ですべての遷移パターンを網羅した、カバー率100%のテストが実行できたのです。

モデルベーステスティングの問題点

ここまで読んでいただいたテスターの方は、少なからずモデルベーステスティングに興味を持っていただいたのではないかと思います。しかし、やはり問題があるのです。

一番の問題は、モデルが大きくなると遷移経路数が急激に増えることです。増え方のオーダーは一般的には言えないのですが、かなりの増えかたになります。もちろん、状態が増えたといっても、分岐の無い一方通行の状態が1つ間に挟まっただけだと、遷移経路数はまったく増えないわけですが、場合によっては1つ状態が追加されただけで遷移経路数が倍になったり、さらに多く増えたりすることもあり得ます。簡単なインストーラーでも10経路、合計遷移数が60、これが少し複雑になると100経路、合計遷移数が1000とかに簡単に増えてしまいます。そして、さらに複雑になるとまた桁が上がり、自動実行できるのに時間がかかりすぎて終わらない、という状態になってしまうのです。

さらに、モデルベーステスティングの根本的な問題として、完全に「形式的」なモデルを入力として用いないといけない点があります。「形式的」というのは、簡単に言うとコードとして記述できる状態で、一点の曖昧さもないものです。大きなプロジェクトではすべての状態を完璧に記述したスペックを用意することはけっこう大変だし、そしてこれを正しくSpec#などで記述するのもまた大変です。Spec#での記述に間違いがあったとしても、多くの場合はその時点ではエラーが出ず自動化コードが生成され、多くの時間をかけてそれを実行した後に遷移失敗エラーが山のように記録されたレポートを見て頭を抱えることになったりするのです。

こうなると、もう一部の状態は考慮しない(そこには遷移しない)ようにしたり、いくつかの状態をひとまとめにしてモデルの単純化を行ったりするなどの工夫を行う必要ができてきて、そのための工数が多くかかってしまうことも考えられます。

それでも時々再考するに値する手法

我々テストエンジニアにとっては、「テスト実行の自動化」の先には「テストケースの自動生成」という大きな山があることは間違いありません。

さらにその先にはモデルからテストコードだけではなくプロダクトコードも自動生成するモデルベース開発(MBD)もあったりします。これは究極のソフトウェア開発の姿のひとつとして考えられているもので、例えばGUIベースの開発環境でモデルを記述し、それを保存した瞬間にCIでプロダクトコードとテストケースおよび自動化テストコードが生成されて、デプロイされたプロダクトに自動生成されたテストが実行されて、その結果がGUIツールにレポートとして戻ってくる。開発者はそのレポートに基づいてモデルを修正していけばプロダクトが完成する、というようなものです。

難しい問題も存在するモデルベーステスティングですが、今後のソフトウェア開発およびテストシーンがどう変わっていくかを見て考えていく上で、テストケースの自動生成を試みてある程度の成功を収めた一例として記憶にとどめておくべき手法だと思います。年々変化していく業界ですので、どこかでまた見直される日が来るかもしれませんし、私は個人的にもそうなることを期待しています。

――――――――――――――――――――――――――――――――――

執筆者プロフィール:水谷 裕一
大手外資系IT企業で15年間テストエンジニアとして、多数のプロジェクトでテストの自動化作業を経験。その後画像処理系ベンチャーを経てSHIFTに入社。
SHIFTでは、テストの自動化案件を2件こなした後、株式会社リアルグローブ・オートメーティッド(RGA)にPMとして出向中。RGAでは主にAnsibleに関する案件をプレーイングマネジャーとして担当している。

お問合せはお気軽に
https://service.shiftinc.jp/contact/

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/