ドリル本を読み返して思い出したこと

同値クラス

先日、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

これをもとに、ドメイン分析テストマトリクスを作ると、有効/無効同値クラスを効率良く作ることが出来ます。

計算式は、画面に出力する値を求めるとき、何らかの判定条件の基準を求めるときによく使われます。

私も実務では使ったことがありませんでした。総当たりテストをしてました(^-^;

読み返して理解できたので、使ってみようと思います。

私の考えるちゃんとしたテストに追加ですね。

私がいろいろな方から教わったり、勉強したことから考えた 「ちゃんとしたテスト」 について書きます

ちゃんとしたテストについて書かせて頂きます。

色々な意見があると思いますが、ぜひお聞かせください。

皆さんの足元に及ばないかもしれませんが、議論をさせてください。

 

↓ のつづき、書きます。

jugemix.hatenablog.com

 

私の考える、ちゃんとしたテスト

単機能テスト

勉強して気づきましたが、自分が昔やっていたのは有則の単機能テストでした。
機能が仕様どおり実装されているかを確認していたからです。

なので仕様に定義されていない箇所のテストを考えられているか、以降は注意を払えるようになりました。
テストだけではなく、設計時にも。

テストの目的

仕様通りに実装されていることの確認です。

テスト設計の流れ

テスト対象の論理を把握する
 
どうテストを設計をするか、つまりテストケースを考えるかについてですが、その前に機能全体を把握している必要があると考えます。
知らない場合は、仕様書から把握するようにします。

ですがその当たり前がないケースも多々あります。
超短納期で設計と実装が並走する、意味がわからない状況もたまにはあります。
辛いですが、そんなときは息抜きを意識して、あきらめないようにしましょう。

これはテスト対象全体を見た時に、その一面だけを捉えてしまうことで、隠された項目や条件を漏らさないようにする為です。
例えば、画面の項目の表示、非表示を制御する設定ファイルの設定値などです。

ですから機能の外側を見て、入力、出力の数を見ます。
それぞれに複数入出力があれば、複数の論理(ロジック、筋道というと分かりやすいかも)があることが分かります。
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でも、カフェでもお酒を飲みながらでも、よろこんでお話をお聞きします。

私が「ちゃんとしたテスト」について書く前に、なぜちゃんとしたテストを考えるようになったかを書きます

はじめに

突然ですが、「ちゃんとしたテスト」って何でしょうか。
これに対する答えを持っている方はそれほど多くないんじゃないかなと思います。
 
しばらく前になりますが、仕事で「ちゃんとテストした?」と聞かれたことがあります。
その時、私は「これはこうで、あれはああで-」と長々と説明をしましたが、
話しているうちに自信が無くなってきてしまい、なんだか言い訳をしている気分になっていました。
 
今から1年半くらい前の話です。
 

思うようにバグを見つけられず悶々とする日々

私はいわゆるシステムエンジニアです。
プロジェクトリーダーをする機会も少なくないのですが、進捗を管理する身からすると納期直前に顕在化するバグほど嫌なものはありません。
 
「なんでこのタイミングでこのバグが?」、「ちゃんとテストしてたのかな?」と、疑心暗鬼に取りつかれてしまいます。
 
「もっとちゃんとテストしたい」
「でもテストの仕方が分からない」
「テストの仕方を聞いても体系的に教えてくれる人がいない」
 
私は、こんな悩みで悶々とする日々を送っていました。
 

総当たりテストとの出会い

ある日、先輩からテストケースレビューをして頂く機会がありました。
 
そこで先輩から「この組み合わせはやった?あの組合せは?」と、組合せの指摘を受けました。
指摘を受けた組合せはやっていなかったので当然やることになりますが、なぜその組合せが大切なのか分かりませんでした。
 
しかし、これをやることでレビューは合格になる為、ケース表のひな形とケースの作成に躍起になっていました。
時間はかかりましたが、チームのメンバーにケース表の書き方を説明して、私が因子、水準の抜け漏れをチェックする-という構図で、協力してもらっていました。
これが「総当たりテスト」との出会いです。
 

テストの自動化

ただ、次第に総当たりテストも辛くなってきました。
テストそのものも時間が掛かるのですが、テストレビューにも猛烈に時間が掛かるからです。
チームのメンバーもテストが嫌になりかけていました。
 
一方で、こなせやれば効果があることも知っていました。
そこで、この大量のテストケースを自動でテストできないかな?と考えたわけです。
 
当時の私は欠陥に心身共にやられていた為、「一つでも特技を身に付けて自分に自信をつけよう」と考えるようになりました。
そして、テストを自動実行するフレームワークの作成に取り組み始めました。
 
いざ始めると色々と勉強することがあります。
プログラムの資格はOCJ-PやOCJ-WCとかを持っているのですが、ペーパープログラマーだったので調べることが多く苦労しました。
seleniumjpの方に色々な場で助言を頂いたりと、たくさん助けて頂きました。
 
ですが、大分時間を掛けてようやく出来上がったと思った時、ふとこんなことを思いました。
 
「あれ?僕は何を自動化すればいいんだろう」
 
 
あ、でも、苦労して出来たプログラムは、結構好評でしたのでよかったです。
テストデータの登録ツールとしてでしたが(笑)
 

テストの勉強を始めました

せっかく作ったテスト自動化ツールなのでちゃんとテストを実行させたいと考えました。
そこで手にしたのが秋山先生の通称「ドリル本」でした。
 
「ちゃんとテストした?」とよく聞かれていたころ、本屋でいくつか購入した本のうちの一冊でした。
 
それまで1、2章を2回くらい読んで挫折した本でした。
当時は開発者経験が浅すぎて、3章以降がぜんぜん頭に入らなかったようです。
 
これは大変勉強になりました。
すぐに実践に活かすことはできませんでしたが、だんだんとテストのイメージがつかめてきました。
当時は、テストタイプ、テスト技法、テストレベルの区別さえつかなかったので、目から鱗でした。
ドリル本を読み終えてすぐに「事例とツールで学ぶHAYST法」も読みました。
テスト設計をするうえでのコツがたくさん紹介されていたからです。
 
勉強を始めてから1ヶ月たったころ、seleniumjp だったか、Nait でお知り合いになった方の繋がりで、「栃木テストの会議」(#toteka)に参加させて頂く機会に恵まれました。
 

チョットデキル人に訊け!

toteka ではこのような企画が予定されており、ドリル本で有名な秋山さんもパネラーとして参加されるということで、チャンスだと思って聞きました。
 
「ちゃんとしたテストってなんですか?」
 
今思うと馬鹿にした質問だったなと思いますが、当時の私にとってみれば必死でした。
これに対して真摯に回答をくださった、秋山先生には頭が上がりません。本当に感謝しています。
 
また、この質問を採用してくださったmiwaさんや、当日回答をくださった和田さん、関さんにも感謝しています。
テスト業界(?)って人にやさしいところだなと改めて思いました。
 

そして「ちゃんとしたテスト」へつづく

それからも色々と勉強したり、これまでの出会った方から教えて頂いたりで自分のテストを成長させてきました。
何も参照せずにまとめられる私のテストはまだこれだけですが、まとめます。
 
まだまだ未熟ですが、読んでみてください。

How to run webdriver(Java) on Firefox 47.0 32bit

色々な文献を照会して試行錯誤した結果、

Firefox47.0をseleniumで動作させることが確認できました。

 

その方法を以下の通り共有します。

 

プログラム

prop.xml (プロパティファイル)

<entry key="geckoDriverPath">C:\Program Files (x86)\geckodriver-v0.8.0-win32\wires.exe</entry>
<entry key="wiresPath">C:\Program Files (x86)\wires-v0.7.1-win32\wires.exe</entry>

<entry key="32bitFFPath">C:\Program Files (x86)\Mozilla Firefox\firefox.exe</entry>
<entry key="FFDevPath">C:\Program Files (x86)\Firefox Developer Edition\firefox.exe</entry>
<entry key="NightlyPath">C:\Program Files (x86)\Nightly\firefox.exe</entry>
<entry key="64bitFFPath">C:\Program Files\Mozilla Firefox\firefox.exe</entry>

 

Driver.java (Firefoxドライバを生成メソッドを定義したクラス)

public static WebDriver createFireFoxWebDriver() {

	// https://id:pw@url/でアクセス可能なFireFox用Profileを生成・ロードする
	ProfilesIni profile = new ProfilesIni();
	FirefoxProfile myprofile = profile.getProfile("SeleniumProfile");

	// geckoDriverではなく、wires.exeをwebdriver.gecko.driverとして指定する
	// System.setProperty("webdriver.gecko.driver", Props.hmProp.get("geckoDriverPath"));
	System.setProperty("webdriver.gecko.driver", Props.hmProp.get("wiresPath"));

	// プロファイルをセットする
	DesiredCapabilities capabilities = DesiredCapabilities.firefox();
	capabilities.setCapability(FirefoxDriver.PROFILE, myprofile);

	capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
	capabilities.setJavascriptEnabled(true);

	// marionetteをtrueにする
	capabilities.setCapability("marionette", true);

	// 32bit版FireFox v47.0を指定する
	capabilities.setCapability("binary", Props.hmProp.get("32bitFFPath"));
	// capabilities.setCapability("binary", Props.hmProp.get("FFDevPath"));
	// capabilities.setCapability("binary", Props.hmProp.get("NightlyPath"));
	// capabilities.setCapability("binary", Props.hmProp.get("64bitFFPath"));

	// (個人的な取り組み)でBasic認証を乗り越える設定を施す(プロファイルに設定しないときはコメントを外す→外してもダメだった。プロファイルに設定するのが無難)
	// capabilities.setCapability("browser.safebrowsing.malware.enabled", false);

	// capabilitiesにプロファイルを指定してドライバを生成する
	driver = new MarionetteDriver(capabilities);

	return driver;
}

 

このような形で@Testを実行したところ、Firefox 47.0 32bit版(≠Developer Edition)を起動することが出来ました。

 

以下は起動したFirefoxトラブルシューティング情報です。

 

アプリケーション基本情報

名前: Firefox
バージョン: 47.0
ビルド ID: 20160604131506
更新チャンネル: release
ユーザエージェント: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
OS: Windows_NT 6.1 x86
マルチプロセスウィンドウ: 0/1 (無効)
セーフモード: false

 

実行したテスト

試しに以下の簡単な処理を実行しました。実行できたseleniumメソッドの報告が目的なので、体裁は無視してます。

@BeforeMethod
createFireFoxWebDriver(); //上記Driver.java記載の処理
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.get(url); // Basic認証が必要なサイトへリクエスト送信する
driver.manage().window().maximize();

@Test
PageObject TopPage = PageFactory.initElements(driver, PageObject.class);
portalTopPage.web_element.click();

@AfterMethod
driver.quit();

 

注意点

http://qiita.com/yssg/items/a054d67bc7c7fc39b276?utm_source=dlvr.it&utm_medium=twitter

こちらで紹介されていた「導入手順#2.GeckoDriverをwires.exeにリネーム」が上記の場合、うまくいきませんでした。(Firefoxが起動しませんでした)

 

そこで「geckodriver-v0.8.0-win32」ではなく、「wires-v0.7.1-win32」を利用したところ、うまくいきました。

これは https://github.com/seleniumhq/selenium/issues/1431 ここで

@AutomatedTester(David Burnsさん)がコメントされていた「Was this using the latest wires release?」というコメントをヒントにしました。

 

上記に至るまでに試したこと。

  1. FirefoxプロファイルをロードせずにgeckoDriverでブラウザを起動する 非Basic認証サイトなら ◯
  2. geckoDriver+Nightlyを使う
  3. geckoDriver+Developer Editionを使う

Testを停止後、Firefoxが起動してテストケースが走るという意味不明な動作をしました。

No.2,3は47.0が起動してしまいました。

 

以上、少しでも参考になれば幸いです。

ReporterとListener

出来事

・テスト自動化ツールを改善した

 

特記事項

・成功/失敗したテストケースの判別

 キーワード駆動テスト特有の課題である。

 TestNGのテストランナーが同一のテストメソッドを実行するように実装している。(少なくとも私のツールの場合は)この為、テストケースを複数回実行するとどれが成功/失敗したのかがレポートでは分からなくなる。

 この対策としてTestNGには、レポート機能を利用する。

 

・ReporterとListener

 Reporterは@Testを付加したメソッド内で有効になる機能である。

 @Test内で実装すると、「Reporter Output」をクリックしたときに右側に表示される「Reporter output for テストスイート」に@Testを付加したメソッドとReporter.log(String hogehoge)のhogehogeを出力することが出来る。

f:id:jugemix:20160613055009p:plain

 テストケース名の重複を許さないような実装にしておけば、どのテストケースが失敗したかはすぐに特定できるようになる。

 Listenerに関しても同様のことが出来る。テスト起動時や終了時等、イベントを拾うメソッドをオーバーライドして利用する。

 

・ツールの設計の必要性

 レポート機能は私がTestNGを使い始めたきっかけでもある。こんなところで生きてくるとは思わなかった。

 どのようなツールが必要で、そのツールを構成するにはどんな要素が必要か、考える必要があると思う。

 今回のツールの目的はマスタ登録後の登録ミスを検知する為のものである。

 この流れの中で登場する人物は以下の通り

   マスタを登録・修正する人

   テスト設計する人

   テスト実装する人

   テスト実行する人

   テスト結果を検査する人

 

 ビューとパースペクティブを使い、アーキテクチャ定義をまとめてみたい。

FactoryとDataProvicerの違い

出来事

・チーズケーキフラペチーノを飲んだ。個人的にはうーんって感じ。

・リフレッシャーズ クールライムを飲んだ。うまい。

・いつもの湯葉の店で昼食を食べた。うまい。

・テストフレームワークを改善した。

 複数のテストケースを別々のインスタンスで並列実行できるようにした。

 

反省

・コーディングに集中し過ぎて家庭での会話がそぞろ。気を付けないと(^_^;)

 

特記事項

・テストフレームワーク改善まとめ

 どんなテストを実行するかによってアーキテクチャ要素(TestNG/JUnit)は変わる。

 

・DataProviderとFactoryの違い

 DataProviderは、スクリプト駆動テストでは、同じテストスクリプトに様々なデータを投入してテストを実行する時に使う。キーワード駆動テストでは様々なテストデータのスクリプトデータを投入してテストを実行する。

 単機能テストで威力を発揮すしそう。

 

 Factoryは、Factoryオブジェクトがテストクラスをインスタンス化して、テストメソッドが実行される。同じテストクラスを別のインスタンスとして実行すると きに使う。

 これでもDataProviderと同じことは実現できる。ただし同一テストクラスのインスタンスを使いまわすかどうかに違いがある。testng.xmlsのsuiteタグで、parallel="method"としてFactoryで実行すると一気にテストを実行できる。

 ・Factory実装のメリット

  複数のテストを同時実行させる場合には大変便利な機能である。

  例1)マルチブラウザテストのとき

    同じテストデータで異なるブラウザテストを実施するケースがあるから、この時はFactoryで各々のブラウザでテストを実行するデータを投入してparallelにメソッドを実行すれば効率的である。

 

  例2)単機能テストのとき

    データプロバイダで同じ種類のブラウザを別インスタンスで起動すれば、失敗したテストが成功したテストの足を引っ張らなくて(影響しなくて)良さそうである。

 

  合わせ技として、DataProviderが返したオブジェクトをFactoryアノテーションが受け取り、@Factoryがついたコンストラクタがそれを引数としてとりながらFactoryクラスによってインスタンス化されテストメソッドを実行させるというやり方もある。

  参考 TestNG – @Factory Annotation Tutorial – HowToDoInJava

     http://testng.org/doc/documentation-main.html#factories

 

 ・Factory実装のデメリット

  DataProviderからテストメソッドにデータを渡すと、どんなデータが渡されたかが分かる。 DataProviderからテストクラスのコンストラクタにFactoryアノテーション経由で渡すと、どのケースによって対象のテストが実行されたかが分からない。

  キーワードテストではテスト実行メソッドは一つだからどのケースが失敗しているのかが補足できないとテストの再現が出来ない。

  Listeners/Reportsを利用して改善が必要

 

以上

ソフトウェアテスト技法ドリルを読み終えて

ソフトウェアテスト技法ドリル

ソフトウェアテスト技法ドリル―テスト設計の考え方と実際

ソフトウェアテスト技法ドリル―テスト設計の考え方と実際

テストのやり方が分からず、情報を模索していた時に出会った本です。

他のどの本よりも具体例を交えて実践的に書かれていたので購入しました。

学ぶことが多く、分からなかったことが整理できたので、それをまとめます。

ソフトウェアテストでやるべきこと (基礎編)

自分がテストをするときの考え方の基礎になったので勝手に命名しました。

単機能テスト

対象機能が仕様通りに動作することを確認します。

やり方としては、機能を構成する入力項目について1項目ずつテストします。テスト対象の入力項目を決めたら、その他の項目には結果が常に真(正常)となる値を設定しながらテストします。その他の項目が常に真となる値にする点がドメイン分析テストに近いなと思いました。

実際に入力値を考える際には、同値クラスを探し、その中から境界値分析をしてすると見つけやすかったです。

組合せテスト

対象機能の処理(論理関係の組合せ)が仕様通りに動作することを確認します。

やり方としては、①仕様として定義されている処理が正しく動作することの確認と、②仕仕様として定義されていない動作の確認に分かれます。

①仕様として定義されている処理の確認

原因結果グラフ、CFD 等のテスト技法で対象機能のチェックなどの論理関係を整理し、論理関係の組合せの結果が仕様通りになるかを確認します。

テストの目的は単機能テストと似ていますが、単機能テストが単一項目の動作に関するテストであるのに対し、組合せテストは入力項目に限らずいくつかの論理関係が組み合わさったときの動作に関するテストと理解しています。

②仕様として定義されていない動作の確認

仕様に記載のない(互いに関連のない)項目同士の組み合わせで意図しない動作にならないかを、HAYST法 やペアワイズ法を用いて確認します。

状態遷移テスト

対象機能、またはシステムに状態がある場合、仕様通りに状態が変わることを確認します。

やり方としては、①状態遷移表、②1スイッチカバレッジ、③2スイッチカバレッジの観点でテストをします。

①状態遷移表

イベントと状態を軸とし、セルに遷移後の状態を記した表で対象機能、またはシステムの状態遷移仕様を表現します。各状態の時にイベントが発生するとセルに記載されている状態に遷移するかどうかを確認します。

②1スイッチカバレッジ

①の状態遷移表で網羅しきれなかった状態遷移について確認します。

ただ、今の課題は行列計算が出来ないので、1スイッチカバレッジ表を作れないこと。簡単に行列計算できる方法を探さないと。

今後のソフトウェアテストで何をするとよいのか

一通りドリルを読んでいくと、開発工程の話が一切出てこないことに気づきました。

状態遷移テストを適用するシーンを考えていてその理由に気づきました。ストップウォッチのように単一機能で状態が遷移する場合もあれば、業務管理システムのように機能間で状態が遷移する場合もあります。だからテストの対象によってどのようなテストをするのかは違うんだと。

絶妙なタイミングでソフトウェアテスト業界で尊敬する方もRTをくださりました。

だからこそのテストアーキテクチャ設計。 RT …自分の場合は結合テストに組み込むことができるけど、単機能で状態遷移するなら単体テストでの実施を計画しないといけない…この工程ではこういうテストをするーみたいなのは一概に言えないね。

それでテストは別に開発手法に縛られるものじゃないよな-と思ったわけです。だからテスト対象を知り、どんなテストをするのが適切かを考えることが大事なんだと。

テストの目的が分かっていなかったころはこんな感じでした。

単体テストってなにやるんだ?」

結合テストって何するんだ?」

システムテストってシナリオテストをやればいいんだよね?」

だから今後は次のことをやっていく必要があると考えてます。

対象機能が満たすべき要件や仕様を理解する

それらは何をもって満たされていると言えるかを考える

それはどのようなテストで確認が出来るかを考える

これらを仕事や趣味で実践しながらエンジニアとしてのスキルを上げていきたいですね。