JUnit4.13のソースを追っかけてみた
先日参加したSQiP「キーワード駆動テストシステムを作ろう」で学んだ、ランナーの役割をJUnitでも実践できるのかを検証する為に、JUnit4のソースコードを読んでみました。
作ったクラス図
折角、なんちゃってクラス図を書いたので公開します。
参考にしたサイト
最初は「ランナーってなんだ?」というところから入って、こちらのサイトを参考にし始めたのですが、分かったような分からないようなままになっていました。
もやもやしたまま、SQiPのチュートリアルを迎えて、ランナーの役割が分かったところで、JUnitのソースを読むと不思議と頭に入ってきました。
途中、こちらのサイトも参考にさせて頂いたり
ihirokyさんは、super.runChild()をオーバーライドしたrunChild()の中で呼び出しています。これも一つの方法ですよね。
BlockJUnit4ClassRunnerを継承したカスタムランナーなので、必ずBefore/Test/Afterの間に実行されるようになります。
また、こちらのサイトを参考にさせて頂いたりしました。
渡辺さんのカスタムランナーは記事でも書かれているように、ユニットテスト以外のテストにも利用されています。なので、run(notifier)からinvokeTest(notifier, testcase)を実行するような作りでカスタムランナーを作られています。面白いです。
結局何がいいのかというと、JUnitを使ってどんな風に「テストを実行したいか」が重要なのかなと思いました。
渡辺さんも書かれていますが、JUnitは「テストケースがクラス毎にメソッド単位で定義されている」というところが原則です。ですから、この考え方に沿ってJUnitを利用するのが、自然な使い方かなと僕も思います。
僕がカスタムランナーを作るとしたら
自分が作っているキーワード駆動テストシステムで共通した画面操作を共通処理に移すにはこうすると思います。
例えば、毎回ログインログアウトが必要なシステムだとします。
これをいちいちテストに書くのは面倒なので、共通処理化してしまいます。
案1)
・カスタムランナークラスの定義
public Class LoginTestLogoutRunner extends BlockJUnit4ClassRunner
・methodInvokerのオーバーライド
@Override protected Statement methodInvoker(...) {
return new CustomInvokeMethod(method, test);
}
・@Testを実行するInvokeMethodのを継承したカスタムInvokeMethodの定義
public class CustomInvokeMethod extends InvokeMethod
案2)
もしくは、JUnitのStatementクラスが「Chain of Responsibility」パターンを利用している事を利用して、Statementのサブクラスを追加しちゃうのも面白いかもしれませんね。
@Testでは、キーワードスクリプトが処理をして、その前後で共通処理を実装できればよいので。
そうすると、テストクラスはシナリオのパターン分できますが、@Testの前後で共通の処理を固定的に実行することが出来ますね。
案3)
@Ruleとして必ず実行させるような仕掛けにしてしまうのも、ありかもしれません。
9/25追記
案4)
カスタムランナーを作らずに済ませる簡単な方法は、@Testに共通処理を書いてしまって、意図した順番で実行する―というのも、一つの手かと思いました。
これなら1クラス=1テストケースとして取り扱うことが出来ますね。
渡辺さんが仰っているように、JUnitの構造上は「1メソッド=1テストケース」ですから、この点を気にしなければこの方法が一番簡単かと思います。
自動でテストを流す時に、実行するクラスが増えますが、Suiteランナーで実行するクラスをまとめてあげれば問題ないと思いました。
まとめ
いづれにしてもJUnitはまだまだ奥が深いし、これを使ってやりたいことはまだたくさんあります。内容を紐解いて自分がやりたいことを深堀した結果を公開したいと思います。
SQiP2016 併設チュートリアルに参加しました (キーワード駆動テスト)
SQiP併設チュートリアルのキーワード駆動テスト勉強会に参加してきました。
目的
- キーワードの粒度、他の方がどのように設計しているのか知りたい。
- 他の方のシナリオテストの準備、検証をどういう考えで実装しているか知りたい。
内容
今回は.NET Frameworkを使った計算機アプリのシナリオテストを、Friendlyというフレームワークをベースとして書かれたMS PowerShellで実装していくという内容でした。
講義
キーワード駆動の概念といった基礎的なお話から、キーワード駆動とテストスクリプトの違い、メリット・デメリットについて教わりました。
デメリットについては、特に「テストケースの増加に伴い、キーワードスクリプト間で重複する部分が出現し、テストのメンテナンスコストを下げる可能性がある」という点が紹介されました。
チュートリアル
キーワードスクリプトを変更するところから始まり、キーワードテストランナーの改修といった点を学びました。
このクラス図は、チュートリアルの資料の取扱いについて小井土さんから許可を頂いたので、テスト実行の入力となるデータも追加して全体の構造を表現してみました。
これが具体的なテスト流れRunTest.ps1の概要です。
(ループ部分は割愛してます)
アクティビティ図を見ると、今回の実装方針ではテストケース(キーワードスクリプト)の実行をつかさどるテストランナーと、テストケースの読み込み、テストセットの実行(テストケースの繰り返し実行)、テスト結果の比較が独立していることが分かります。
これは、今回のテストシステムの設計がキーワード駆動テストのデメリットである「共通部分の重複」を排除することを意識している為です。
これはテストケース実行処理部分=テストランナーのフローです。
例えば、ログイン→商品選択→決済→ログアウトというシナリオがあったとき、①商品選択だけ1つも選ばない、②1つ選ぶ、③配送しきれないほど選ぶ―といったバリエーションを持たせてテストをたいとします。
これをキーワードスクリプトに書くと、スクリプト上に①~③で3回ログイン、決済、ログアウトが現れます。
今後のメンテナンスでログイン処理に手が加わったらどうなるでしょうか。
上記のテスト3スクリプトとも直さなければ動かないテストになってしまいます。
アプリケーションの修正に伴い、自動テストもメンテナンスは必要です。
この前提に立って、3つを直すより1つを直す方が運用しやすいという考えの元、ランナー側で共通部分を実行するように実装していました。
実運用ではアプリケーションのライフサイクルを考慮して、ランナーを設計することが望ましいと思います。(私見)
自動テストシステムにおけるランナーの役割は、テストの実行順や実行方法の制御だけでなく、キーワードスクリプトにおけるコードとして実装された共通処理を実行するという役割も担っていました。
後日 JUnitで実装する場合の調査
同じことを自分の作る自動テストシステムでも実現できるかな?と、JUnitのランナーの構造について後日調べてみました。
JUnitの場合は、@Beforeや@Testといったアノテーション付のメソッドブロックをその名もBlockJUnit4ClassRunnerが、methodBlockメソッドでStatementというテストの文脈(実行順のようなもの?と理解してます)オブジェクトを作り、ParentRunnerのrunLeafメソッドでオブジェクトの一つ一つを実行することでテストを実行しています。
もしテスト実行の共通処理をまとめるのなら、BlockJUnit4ClassRunnerのサブクラスでmethodBlockメソッドをオーバーライドするか、methodBlockが呼び出すInvokeMethodクラスのmethodInvokerサブステートメントを実装する感じになりそうでした(JavaDocにもそう書いてありました)
この為、JUnitを使う場合でもカスタムランナーで吸収することは出来そうです。
これもParentRunnerがrunChildメソッドを子クラスに委譲してくれているおかげかなと思います。
ただ、JUnitの構造を理解するところから理解する必要があり、長くなりそうなのでまた後日記事にまとめます。
参加してよかったこと
- ランナーを使ったテストケース間で重複したテストコードの排除の方法
- 想定結果の準備方法
- テスト結果の検証方法はテストの目的によって異なるので、自動化する前にテストを設計すること
- 回帰テストは前回のテスト結果と比較すると良いこと
- バグの再現手順をテストケースとして実装すると良いこと
自分がキーワード駆動テストシステムを作る上で参考になる知見、気づきを得ることが出来ました。もっと実践と研究を繰り返すことで、世の中の自動化に寄与するアイディアを生み出せるんじゃないかなーと思うようになりました。
参加してよかった。
Java SE Javadoc Hobber の日本語文字化けを正す手順
コーディング中にJavaSE標準のAPIにマウスカーソルをかざすと、Javadocがホバーしますよね。
私の環境(Windows 7/Eclipse Mars)では以下の問題が発生していました。
ネットで情報を調べても分かりにくかったので私の解決方法をシェアします。
-
メニューから、「ウィンドウ>設定」をクリックします。
-
設定画面で、「Java>インストール済みのJRE」をクリックします。続けて、プロジェクトでビルドに使用しているJRE/JDKを選択し、「編集」ボタンをクリックします。
-
JREの編集画面で、「JREシステム・ライブラリー」をCtrl+Aキーで全選択し、「Javadocロケーション」ボタンをクリックします。
-
開いたJavadoc画面で、「Javadocロケーション・パス」に「https://docs.oracle.com/javase/jp/8/docs/api/」を入力し、「検証」ボタンをクリックします。このパスには、「手順2」で選択したJREのバージョンと同じバージョンのjavadocを指定してください。インターネットで、「Java SE 8 japanese docs」と検索すると以下のサイトが検索できますので、これを指定します。
※1 英語のサイトもあるので、お好みでどうぞ。※2 「アーカイブ内のJavadoc」では、Oracle社のWebサイトからJavadocをダウンロードして、ローカルファイルから参照することもできます。
-
次のようなメッセージが表示されたら、コーディング中にJava SEのAPIにマウスをかざすことで現れるHobberに日本語のJavadocを表示することが出来ます。
- 結果は、下図のようになります。
-
この時、「手順2」で指定したjreを使用しているプロジェクトの設定が「手順8」のような設定になっていないと、下図のように化けてしまうので注意が必要です。
- パッケージエクスプローラで、「手順2」で指定したjreを使用しているプロジェクトをクリックし、Altキー+Enterキーを押して、そのプロジェクトのプロパティー画面を表示します。ファイルのエンコードの種類は、ご利用の環境に依存する場合があるので、ご注意ください。
初めて使うAPIの場合、Javadocの有/無によって生産性が変わってくると僕は思いますので、直しました。皆さんの生産性もこれで上がればいいなと思います。
スプリントと振り返りについて思ったこと ~ウォーターフォールとアジャイルの議論より~
こちらのサイトで紹介されていた「スプリント」、「振り返り」の考え方を自分の置かれた状況で活かすと、長期的みて仕事の効率が上がるのではないかと考えたのでメモします。
まず、このようなことを考えた経緯をまとめます。
ウォーターフォールとアジャイル
6月21日(火)にJJUG会長の鈴木さんが主催されたワークショップに参加しました。
そこでは以下のような紹介をされていました。
アプローチの考え方の違い
このワークショップではそれぞれの方法論を、マネジメントの観点からそれらの違いについて説明されていました。
私の理解を一言でまとめるとこんな感じです。
その理由は、感嘆するほど納得いくものでした。
ゴールまでが見通せるているなら、最初に計画を立てたほうが管理しやすいから。
一方で、見通しが立てにくい事柄に取り組まなければならないなら、見通しが立てにくいと失敗もしやすいので、それを見通しを立てやすいタスクまで分解して、その単位で計画的に進めていく方が成功しやすいから。
こんなブログに突っ込む人なんかいないでしょうけど、原理的な思想については、詳しくないので突っ込まれても困ってしまいます(笑)
今はこういう説明に納得しているというだけです。
マネジメントの観点
PDCAという言葉がありますが、鈴木さんはマネジメントの基本はこれだと仰っていました。
有期性のある活動(仕事)において、それがうまくいかない場合はこれのどれかが失敗しているということだと。
それぞれの方法論には粒度は違えどフェーズ(設計、製造、テストなど)があるので、フェーズごとにPDCAを実践する点においては本質的には違いはないんだなあと思いました。
おかれている状況によって、採用する仕事の管理方法が違うだけ。
方法論の目的、技法の適用シーンを理解することの大切さ
仕事を上手に進めるには、その仕事で採用する方法論の目的、適用すると効果が上がる状況をきちんと理解して、採用するのが妥当だという鈴木さんの意見には私も賛成でした。
テストをされている方ならわかると思いますが、テスト方法論やテスト技法についても似たようなことが言えますよね。
例えば、(短絡的な例えですがー)設計書が無くて、テスト対象に対して深い知識やテストスキルが高い人がいるような状況なら探索的テストをやろうかとか-です。
効率的に仕事を進める為に
今の仕事は、開発以外にも見積や問合せへの応対など様々な作業があります。
色々な経緯から仕事量自体が去年より減ったのですが、正直もっと仕事をしたいと思っています。
こんな思いで悶々としていたときに、今の仕事をもっと早く終えられれば、同じ時間でもこなせる量は増えるよな-なんて思った訳です。
そこから自分の作業時間を測って自分を管理しようと考え始めました。
毎日の作業をログに残して、ログには作業時間を書きます。そうすれば自分の力量が見えるだろうと思ったわけです。
始めてから1ヶ月立つのですが、集計が大変で全然できていないのが現状でした。
スプリントと振り返り
そんな時に冒頭で紹介した記事を読んで、アジャイルプラクティスであるスプリントと振り返りを参考にしてみようと思いました。
幸いなことに、私はタスク管理表を付けているので、一定のスプリントで作業計画を立てることは出来そうです。タスクを細かい作業単位に落とし込むというところを今までやっていなかったので、ここを細分化して取り組んでみたいと思っています。
大変にならない程度にやってみて、スプリント終了時に振り返りをしてみたいと思います。
これで作業見積りの精度が徐々に上がっていけばよいですし、人に作業をお願いもしやすくなると思います。
状況を判断する力
私の場合は、このような仕事の仕方だったので適用できそうです。
しかし、既に仕事内容がマニュアル化されていて、その手順で最高の結果を最高のパフォーマンスで出せるのならそれでいいと思います。
私もそれに従います。
状況によって適切な方法を判断して、自分の力として利用できるように知識として持ってように常にアンテナを張っておきたいな、と思いました。
WACATE2016夏に参加して、成長しそうな予感の私のテスト
テスト分析
分析の手順
やり方を以下のように、実行可能な作業単位に分けられていた点も、とてもありがたかったです。
- 分析方法を決める
- 情報を整理する
- 成果物を確認する
- 顧客の要求(テスト要求)を分析する
- 設計書(テスト対象)を分析する
- 分析結果を整理する
分析方法を決める
テストしたい「こと」? テストしたい「ところ」?
テスト分析の手順を振り返っていて、混乱してしまったのがここでした。
- "システム"(ドキュメントすべて)に対して分析をしたら、テストしたい"こと"、"ところ"って粒度が異なる"こと"、"ところ"がたくさん出るよなあ
- 粒度の違うテスト条件、どうやって整理するんだろう?
- 粒度が異なるから、それぞれの粒度か、テスト条件が一度にたくさん出てきてしまい、まとめきれないんじゃないの?
などなど
情報(分析する対象)の整理
ここで、この混乱を解く為に重要な鍵となるのが「情報(分析する対象)の整理」でした。
ここでの分析対象は、配布された資料です。
当日、テスト分析、テスト設計の為に配布された資料(顧客要求、仕様書)はたくさんありました。テスト設計まで行うので仕方のないことです。
ですが、これらを整理すると、いくつかに分類できることに気づきます。
- 新旧業務フロー画面遷移図
- 各種定義書
- テストに関する顧客要求
テストし易い単位から分析すれば、その単位(同じ粒度)でテスト対象を洗い出せるのではないか、ということに気づきました。
分析対象が何かというと、上記の整理した資料です。ですから、同じ分類や粒度が同じ分析対象を、一つずつ見ていけば良かったのです。
落ち着いて考えれば当たり前なことでしたが、情報を整理しないと、こういう混乱を招くという良い教訓になりました。
いきなりすべての資料(システム全体)に対して、分析をするのではなかったのです。分析対象が大きすぎますしね(^-^;
また、これに関連して気づいたのは、テストレベルが対象とする単位、粒度で考えてもよかったなということです。
V字モデルではテストをする順番は単体(単機能)テスト、統合(複数機能)テスト、システム(機能全体)テストですから。
しかし、私はやはりテストレベルから考えるより、分析対象を整理してから、その整理した情報ごとに分析をしていく方がしっくりくるようでした。
テスト設計技法が適用できるテストレベルはある程度示されていますが、テストレベルに対応するテストタイプは、テスト対象によるーとなってしまうと思うからです。
限定された業界や業務ならば、後者の考え方でテストタイプを限定しても良いかもしれません。
分析をすることのメリット
ただ、やはり分析をすることにはメリットがあります。
グループワークの発表や秋山さんの講義でも紹介されていましたが、どうやってテスト対象を導きだしたのか考え方を人に伝えられる、という点です。
「ちゃんとテストした?」と聞かれる人(私を含め)には、とても効果的だと思いました。
テスト分析の結果として、やるべきテストが決まる
昔「やるべきテストはテストレベルごとに決まっている」と私は思っていました。そういうものだと、思い込んでいました。
などなど
何をテストしたらいいのか分からないのは、テスト分析ができていないから
ここまでくると自分が何をすべきかは、もう分かります。
分析が上達すれば、テストするところはここだよって言えるようになるわけです。
ですから、私のテスト上達の鍵はテスト分析が上達することだと分かりました。
WACATEに参加した一番の収穫です。
振り返りしなかったら気づけなかったと思います。やっといてよかった。
分解
テスト分析の上達の為に大きなヒントになりそうな手法が、「分解」です。
秋山さんが講師として紹介してくださいました。
講義では要求が大きい場合、分解を利用して、具体的な要求を引き出していくと良いと教わりました。
USDM のような思考のフレームワークを使うと、上手に分解できるそうです。
- 時系列
- 構成
- 状態
- 共通部分
分解した結果を説明できるように一枚にまとめる
- 氏名
- 住所
成果物の確認
以上の分解によって成果物が出来上がります。
テスト分析の成果物は、テスト設計のインプットとなります。
あとはテスト分析の成果物に対して、テスト技法を適用してテストを設計(テストケースを作成)していくだけです。
ここまでで、テスト分析がテストの質を左右することが容易に分かりますね。
これをテスト計画やテスト者への指示に反映することで、チームとしてより良いテストが出来そうだと思いました。
チームの方への感謝
グループワークの最後に細川さんから、「テスト分析、テスト設計出来た?」という質問がありました。
私たちのチームは、テスト設計は「う~ん」でしたが、分析は「出来たと思う」人がほとんどでした。
成長しそうな予感の私のテスト
ドリル本を読み返して思い出したこと
同値クラス
先日、Twitterでだして下さったJSTQBの問題で、BMIの計算式がありました。
その時の論点は、式の結果の種類から同値クラス数を考えるものでした。
その時、身長が0の人はいないからどうするのかな?、マイナスのときはどう?と思いましたが、私は無効同値クラスとしてテストは必要だと思います。なので、同値クラスは5つかなーと思いました。
ドメイン分析テスト
ところで、これドメイン分析をすると、どんなテストケースが導けるでしょうか。
式には複数の変数があります。
その変数には同値クラスがあります。
それぞれの変数のon /off / inを考えると、効率良く同値クラスを検証するテストが出来そうですね。
身長(単位cm、有効桁数を小数点第一位まで)
on / off を考えると、off=0、on=0.1としましょう。in=160
体重(単位kg、有効桁数を小数点第一位まで)
on / off を考えると、off=0、on=0.1としましょう。in=60
これをもとに、ドメイン分析テストマトリクスを作ると、有効/無効同値クラスを効率良く作ることが出来ます。
計算式は、画面に出力する値を求めるとき、何らかの判定条件の基準を求めるときによく使われます。
私も実務では使ったことがありませんでした。総当たりテストをしてました(^-^;
読み返して理解できたので、使ってみようと思います。
私の考えるちゃんとしたテストに追加ですね。
私がいろいろな方から教わったり、勉強したことから考えた 「ちゃんとしたテスト」 について書きます
ちゃんとしたテストについて書かせて頂きます。
色々な意見があると思いますが、ぜひお聞かせください。
皆さんの足元に及ばないかもしれませんが、議論をさせてください。
↓ のつづき、書きます。
私の考える、ちゃんとしたテスト
単機能テスト
勉強して気づきましたが、自分が昔やっていたのは有則の単機能テストでした。
機能が仕様どおり実装されているかを確認していたからです。
なので仕様に定義されていない箇所のテストを考えられているか、以降は注意を払えるようになりました。
テストだけではなく、設計時にも。
テストの目的
仕様通りに実装されていることの確認です。
テスト設計の流れ
テスト対象の論理を把握する
どうテストを設計をするか、つまりテストケースを考えるかについてですが、その前に機能全体を把握している必要があると考えます。
知らない場合は、仕様書から把握するようにします。
ですがその当たり前がないケースも多々あります。
超短納期で設計と実装が並走する、意味がわからない状況もたまにはあります。
辛いですが、そんなときは息抜きを意識して、あきらめないようにしましょう。
これはテスト対象全体を見た時に、その一面だけを捉えてしまうことで、隠された項目や条件を漏らさないようにする為です。
例えば、画面の項目の表示、非表示を制御する設定ファイルの設定値などです。
ですから機能の外側を見て、入力、出力の数を見ます。
それぞれに複数入出力があれば、複数の論理(ロジック、筋道というと分かりやすいかも)があることが分かります。
HAYST 法において利用されるラルフチャートに近いかもしれません。
論理毎にテスト項目を探す
次に、論理一つずつに焦点を当て、その観点で機能の内側を見ていきます。
例えば、商品マスタ登録画面に、登録、削除、更新の機能があるなら、その3つの観点それぞれで見ていきます。
論理を一つづつ見ていくのは、経験的に処理毎に使われる項目が変わるかもしれないからです。
もしかしたら登録した商品コードはキーとして使われる為、更新できないかもしれません。
そうなると、更新時のテスト項目と、登録時の項目とは同じにはなりません。
ですから、私は単機能のテスト設計は論理ごとに行うと良いと考えました。
ところが、中には複雑な論理を1つの画面で実現する処理もあったりします。
そういう時は、テスト技法を活用すると良いです。
便利な技法
上記を支援する技法としては、論理を表現する、原因結果グラフ、CFD があります。
テスト技法としても紹介されるものですが、ここではツールとして紹介します。
私は、シンプルさと定義外の論理が見えてくることからCFDをプログラマさんとのテストケースレビューで使ったりします。
紙にちょろっと書く程度ですが、仕様を知らない場合、初めに論理の認識合わせをしてからでないとテストケースをしても効果がありません。
ですからレビューをするために書くのです。
本当は設計にこれら技法で表現された図があるといいと思っていますが、そうもいかないことが多いですから。
論理のテスト前に、単機能(単項目)のテスト
話を戻します。
論理を書いた後ですが、すぐには仕様としての論理の検証はしません。
なぜなら、その論理を構成する要素(単項目のチェック処理や、分岐条件の導出など)に誤りがあると、論理を作り直し(プログラム修正)になるからです。
プログラムを作り直したらテストはやり直しです。
私の場合は、ユニットテスト(≠単体テスト)を(書いてみたいけど)書いたことがない(書けない)ので、手作業でやり直しになります。
これは辛くて耐えがたい作業なので、ちゃんと単項目のテストをしようと考えました。
これはユニットテストの考え方に通じるものがあります。
アーキテクチャ構成要素の最小単位が検証され、品質が保証されていれば、そのアーキテクチャ構成要所の最小単位で構成される要素も同レベルの品質が保たれる可能性はあります。
この一方でアーキテクチャを構成する要素の中で一番数の多い最小単位の品質が悪いと、品質は一番低いものに足を引っ張られる特徴がありますので、システム全体の品質もその程度になってしまいます。
単機能テストのテスト技法
単機能をテストするときに確認するポイントは大きく2種類あります。
単項目の仕様(書式、値のチェック処理など)
単項目の仕様をテストする場合は、同値分割、境界値分析があります。
単項目の種類(文字、数値、日付、コードなど)に着目して、仕様から同値クラス、境界値を分析するのがポイントです。
また、テストを流す時はテスト対象外の項目はデフォルト値にすることがポイントです。
テストをしたい項目に他の項目の値が作用することを防ぐためです。
複数項目が関連するチェック処理
複数項目チェック処理をテストする場合は、デシジョンテーブルを作り、分岐条件を整理します。
上では原因結果グラフを論理を整理するツールとして紹介しましたが、ここではテスト技法として紹介します。
これを書けるようになるとCEGTestという、私がWACATEを知るきっかけをくれた方が作成してくださったツールが、圧縮済みのデシジョンテーブルを出力くれます。
私はこのことが便利なのは知っているのですが、僕はまだ原因結果グラフを書けないので、出来る範囲でデシジョンテーブルを作って圧縮せずに網羅的に整理してしまっています。
以上が単項目テストの設計手順です。
このように、ちゃんとした単項目テストを考えるようになりました。
皆さんの単機能テストはいかがでしょうか。
組合せテスト
単機能テストでは論理ごとにテストをしてきましたが、論理毎に見てもそれだけでは安心できません。
本来、論理毎に使われる内部的な変数を共有している可能性があるので、組合せテストをする必要があるのです。
テストの目的
論理内、論理間で使われる単項目を組合せた時に、仕様にない組合せで意図しない結果を引き起こさないかを確認することです。
組合せテスト設計技法
HAYST 法による直交表やオールペアがあります。
HAYST 法は実体験したことがないので、ペアワイズとどれだけバグ検出に差が出るのかは何とも言えませんが、テスト項目の導出だけならPairWiseを良く利用します。直交表を作る手順を整理できていないのと、PICTという便利なツールがある為です。
ですが、テスト設計の為には、HAYST 法 で紹介されているFV表、ラルフチャート、FL表の活用が有効だと考えています。
以上、単機能テスト、組合せテストは必ず単体テストのテストレベルで実践します。
組合せテスト2
私は組合せテストの考え方は、複数機能間のテストにおいても利用できると考えています。
余談
いきなり余談ですが、私はテスト設計について以下のような考えを持っています。
- 有効なテストケースを作成するテスト工程の一作業である
- テストケースの作成には、テスト技法、経験的に有効であると認められた知識としてのテストケースを取り入れることが、効率的で効果的なテストケース作成に有効である
私は様々なテスト技法の活用シーンを理解しておけば、「どのテストタイプ、どのテストレベルでどんなテストをしたらいいか」という疑問は少なくなるのではないか考えています。
「◯◯は死んだ」が今話題ですが、人(組織・チーム)を見て、技法(技術)を効果的に適用できるシーンから、適切なインテグレーション(適用、統合)の方法を考えればよいだけのことだと思うのです。
その人にとって見れば◯◯が合っていて、効果があればそれでよいのです。
機能間テストへの組合せテストの応用
ですから、複数機能間のテストでも、複数機能を一つの業務や作業のまとまり(サブシステム、機能よりも大きなまとまり)と考えて、テスト対象の因子をHAYST法で紹介されている6W2Hで分析していくと良いと思います。
例えば、「商品を出荷する」という作業のまとまりは、次の通りの作業で構成されていたとします。
・出荷指示を貰う
・出荷対象を在庫から引当する
・出荷対象をピッキングする
・出荷対象を検品、梱包する
(・出荷対象に宅配便伝票を貼る)
(・出荷対象を運送業者に渡す)
・出荷対象を出荷した記録を残す
※()は人手の作業
「出荷対象を検品、梱包をする」に改修が入った場合、「ピッキングしてきた出荷対象」が正しく検品できるか、が気になります。
また、「検品した出荷対象」に対して、「出荷した記録を残せるか」が気になります。
このように、作業を構成する機能間のインタフェースに不整合が無いことを確認できれば、既に単機能でのテストをしているので、上述した「商品を出荷する」の業務は滞りなく行えることを保証できます。
しかし、「ピッキングの商品リストを出力する作業の前に「商品名称の修正」をしたとしましょう。
普通に(?)設計されていれば、注文受付済みのトランザクションが、マスタを参照するような設計はしないですが、万が一設計か実装に欠陥があったとします。すると、業務担当者が商品名でピッキングしていたら、AでピッキングするはずだったのにBをピッキングすることになってしまいます。
このような一見関係のない機能間の処理によってデータの状態が変わってしまうような欠陥もあります。
組合せテストには、「有則/無則」という考え方があります。(禁則もありますが、理解が浅いので割愛します)
仕様の確認は「有則」のテストです。
仕様にない欠陥の発掘をするのが「無則」のテストです。
よって、無則のテストでは因子の1つにテスト対象の業務を構成する2機能(2水準)、もう一つの因子に水準に無関係な機能をN水準として、無則の組合せを考えます。
テスト対象と無関係な機能とは
これは、テスト対象機能で利用している情報を更新、削除する可能性のある機能と考えると良いです。
テスト対象機能において、SQL でマスタと結合してデータを取得してくることが出来る項目があったら、そのマスタを無関係な機能とすると良いです。
正常系の処理をしていた時は問題なく処理できていても、途中でその取り扱うデータの状態を変える可能性のある処理をしたときに思わぬ影響を及ぼすことがあります。
組合せテストではこのような利用方法がありますので、統合テストのテストレベルでも心がけるようにするようにしています。
状態遷移テスト
機能間の組合せという点では、システムやデータの状態についても、同様のことが考えられます。
状態遷移テストの目的
機能間の組合せテストでは、状態ではなくデータ不整合の有無に着目をしますが、
システムやデータには状態があり、ここで整理する状態遷移テストではそれら状態の正しさを確認します。
状態の特徴
データの状態は様々な処理の条件となる場合が多いです。
例えば、「ネットでの注文を確定するときの条件」です。
ネットでの注文には「品切れ」という商品の状態があります。
商品を選んでいた時は在庫があっても、注文確定時には商品が品切れになっている場合があります。
商品がカートに入っているからといって、品切れの商品を注文できてしまってはクレームに繋がります。
このように状態に着目してテストをするのが状態遷移テストです。
テスト技法
これらは、トリガーと状態の状態遷移表を書くとテストすべき仕様をきれいに整理できます。
また、状態遷移表を元に、遷移前、遷移後の状態の関係行列を作ると有則、無則の状態遷移をチェックできるのでおすすめです。
つまり、状態遷移表では仕様にあまり記述されない無則の部分の見落としを防ぐことが出来ます。
組合せテストと同様に、遷移が無いはずの処理を実行したときに、状態が遷移したりしないか注意することが出来るようになるので、よりバグが潜んでいそうなところをテスト出来ます。
更に、関係行列を2乗した1スイッチカバレッジ表まで作って、全パターンテストをすると内部の変数の故障などが見つかって良いです。
以前この関係のバグを見つけたときの例をツイートしたのですが、忘れてしまったので、思い出したらまた書きたいと思います。
シナリオテスト
シナリオテストも同じように、有則、無則の考え方を取り入れてテストをします。
テストの目的
システムを導入、改修して改善に取り組もうとした当初の目的を達成できているかの確認です。
改善するパターンをシナリオとして、そのシナリオをなぞります。
しかしなぞるだけでは仕様通りになっている事しか確認できません。ここでも有則・無則の考え方を適用します。
- 正常シナリオ
- 準正常シナリオ
- 異常シナリオ
この3点について考えてシナリオに対する考慮の抜け漏れを確認します。
また、シナリオを考えるときはHAYST 法の6W2Hで、考えると良いです。
(先日のリナさんと秋山さんのツイートを見て)ユースケーステストとは違うので要注意です。
シナリオテストはまだそれほどやり方を確立できていないので、この辺にしておきます。
ぜひ皆さんのシナリオテストを教えてください。
チームで一定のテストをすることのむずかしさ
この様に考えても、チームメンバーにその通りに実践してもらうのがなかなか難しいです。そもそも一定のテストをしたのは、テストケースの作成レベルにバラつきが多いからでした。
ですから、私の今の課題は、以上を実践して、メンバーからフィードバックをもらい、改善して、設計結果を全員でレビューしやすいフレームワークにすることです。
ちゃんとテストして嫌な思いをしたくないですから。
チームで一定のテストを実践、フィードバックを貰う為に取り組んだこと
実践してもらうにしてもある程度のフレームワークが必要です。
そこで、私はこの手順をテスト計画書の雛形として書き込みました。
私がいるチームでは作業をお願いする方が頻繁に入れ替わります。
その都度説明をするのは骨が折れます。ですから、計画書にして形式知にすることにしました。
実践したことの評価
しかしこれだけでは定性的な評価のままで、テスト設計の為のフレームワークのエコシステムは成立しません。
計画時に評価指標を定義して、計画時に想定した指標に対してレビュー時に評価しようと考えています。
陳腐化対策
さらに、仕事を一緒にしている人、WACATE のような勉強会で出会った方からの意見を頂いて的外れなことを言っていないか確認したいと思っています。
今日ここに来たのもそのためです。
まとめ
以上が、私が教科書を噛み砕いて、色んな方に教えて頂いて考えた、 今の実践する必要があると思っているちゃんとしたテストです。
もっとたくさんのことを学んできたはずなのですが、自分からアウトプットできないということは勉強したことが定着していない証拠だと思います。
これが私の実力だと真摯に受け止めて、これからは特に実践に励んでいきたいなと思います。
ぜひ皆さんのちゃんとしたテストについてもお聞かせください。
TwitterでもFacebookでも、カフェでもお酒を飲みながらでも、よろこんでお話をお聞きします。