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

はじめに

突然ですが、「ちゃんとしたテスト」って何でしょうか。
これに対する答えを持っている方はそれほど多くないんじゃないかなと思います。
 
しばらく前になりますが、仕事で「ちゃんとテストした?」と聞かれたことがあります。
その時、私は「これはこうで、あれはああで-」と長々と説明をしましたが、
話しているうちに自信が無くなってきてしまい、なんだか言い訳をしている気分になっていました。
 
今から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 …自分の場合は結合テストに組み込むことができるけど、単機能で状態遷移するなら単体テストでの実施を計画しないといけない…この工程ではこういうテストをするーみたいなのは一概に言えないね。

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

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

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

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

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

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

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

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

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

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

I read "Buying Somw Gloves".

今月からはじめた英語学習の一環で、簡単な本を読みました。

ラダーシリーズ「手袋を買いに」

情景がイメージしやすくすらすら読めました。

中学二年生レベルに語彙で記述されているレベルでしたが幾つか読めない熟語がありました。

hold out ~を差し出す

このレベルならどんどん読めそうです。次はなにを読もう。。

How To Pass MS 70-532 to 534

Azureに関する知識を深めたいと思い、MCSD70-532~534を次の目標にしました。合格した人がどうやって勉強したのか情報を集めました。

  • 70-532の概要

https://www.microsoft.com/ja-jp/learning/exam-70-532.aspx

  • 70-534の教材紹介ドキュメント(MS Learning)

https://borntolearn.mslearn.net/b/weblog/archive/2015/05/18/mcsd-azure-solutions-architect-study-resources-you-need-to-know

  • MS MVP Chris Pietschmann氏による70-532合格体験記

http://pietschsoft.com/post/2015/06/06/How-I-passed-the-70-532-Developing-Microsoft-Azure-Solutions-certification-exam

  • 上記のChris Pietschmann氏 が70-532学習過程でまとめられた資料

http://buildazure.com/

  • Chris Pietschmann氏が作成したテスト

http://crpietschmann.github.io/Azure-70-532-Practice-Test/?

  • YouTube に紹介されていた動画

https://youtu.be/gTpX4tZkYkw

 

その他、順次学習を進めていきたいと思います。