[Lesson Test Automation. Day 07] Test Automation Code Design vol.04


Outline

本コンテンツは、これからテスト自動化を始める人向けに作成するコンテンツ。
筆者のこれまでの経験を元に作成しているので、教科書と異なる場合があります。

今回は、テスト自動化の実装にあたって、どのようにプログラムを組むとよいかの設計に関することを記載する。
尚、開発言語に依存しないレイヤーである、概念について記述する。

前回に引き続き、テスト自動化設計に関して執筆する

Test automation design view point

1.Data driven
2.Data normalization
3.Keyword driven
4.Robust & Sensitive
5.Scenario independency
6.Scenario size
7.Setup & Teardown
8.Analyzable report
9.Repeatability
10.Break flaky
11.Flexible trap

9.Repeatability

再実行が可能なスクリプトかどうか。
これまで述べてきた、「5.Scenario independency」 や 「7.Setup & Teardown」と重複するものがある。

テストスクリプトが単体で何度でも繰り返し実施が可能であることを求めているものである。

まず必要性に関して。
[Lesson Test Automation. Day 04] Test Automation Code Design vol.01のテスト自動化の利用前提として

・各テストシナリオを基本的に毎日実施
・毎日JENKINSのステータスを確認し、失敗したスクリプトがあれば調査し、問題解決後再実施し成功にする

と述べています。
この前提で、Repeatabilityが重要になってきます。

なぜなら、毎日実行し、その上失敗すれば問題解決するために一日に何回も実行を行う可能性があるからです。

次のようなテストシナリオの場合、Repeatabilityを考えて実装しないと運用上支障が起きる場合がある

  1. 会員は一つのメールアドレスに対して一回しか申し込むことができない(退会可能)
  2. 会員は一つのメールアドレスに対して一回しか申し込むことができない(退会不可)
  3. お気に入り登録
  4. プールしている金額の範囲で物を購入できる
  5. ゴルフのような、日付指定した予約処理

会員登録の処理でも、1のように退会できるのであれば
会員の状態をリセットすることができ、Repeatabilityは保てる。
会員登録 ⇒ 退会 のセットのscenarioを自動化で組めばよい。

ただ、一度利用したID(メールアドレス等)に対して、1度しか登録できない場合、厄介である。
その場合、任意のID(メールアドレス)を作成し、処理することで回避できる
ID(メールアドレス= \${unixtime}@gmail.com )作成 ⇒ 会員登録 

お気に入り登録など、ユーザーになんらかのデータを保持する処理は、その保持を解除するような処理で回避できる
お気に入り登録 ⇒ お気に入り削除

プールなど事前に入金した範囲で物を購入する場合、開始時に入金する処理を組むことで回避できる
残高が蓄積していくため、最初にリセットを行うと、残高のvalidateを仕込む場合に有効である
残高リセット ⇒ 入金 ⇒ 購入

日によって、使用するデータが異なる(例えば、ゴルフの予約)場合、データ指定をする部分を実装する等の工夫がいる

例えば、予約する日を \${yyyy}/\${mm}/\${dd} と可変(例えば実行日+7日)にする。
もしくは、データソース側が可変になるように、例えばデータソースとしてexcelを使用している場合、MACROで日付を可変にする。

10.Break flaky

まず、Flakyとは?
下図に、Jenkins(test automation)の実行履歴と成功率を示しています
グリーン = 成功
レッド = 失敗


これはずっと成功が続いています。
まったくもって問題がありません。


成功率は3つの例の中では一番悪く、11回連続失敗が続いています。
ただ、これはFlakyではなく、明確な原因があって失敗が続いていたものと思われます


これは、成功、失敗を交互に起こしています。
これをFlakyな状態と呼びます。
script上基本的には問題はないのですが、成功したり失敗したりします。

日々、test automationを実行する場合、このようなFlakyなscriptは運用が多く発生し、非常に厄介なscriptになります。
そのため、このようなFlakyなものが発生しないようにすることが重要となる。

- 実行開始時に、初期化を行う。(不適切な環境状態から開始して失敗することを防ぐ)
- 実行終了時に、クリーニングを行う。(不要データ削除など、次回他のテストが動かしても問題ないようにする)
- テストが失敗した時、壊れた環境、途中のトランザクション等をクリアにする
- テスト環境のリソースが複数のテスト実行で衝突しないようにする。(互いに干渉するテストの場合)
- 十分なスペックのテスト環境
- 待つ処理がある場合、ランダムなwait時間を使う
- タイムアウトなどで失敗するときは、リトライなどを入れる

最初の二つ、データの初期化、クリーニングは、"7.Setup & Teardown"で述べた通りです。
開始時はデータが変な状態である前提で、それを毎回クリアにしてから開始するようにします。
終了時は次の実行に易しくなるように、クリアしましょう。

3番目のテスト失敗時のクリアも、"7.Setup & Teardown"で述べた通りです。
途中で失敗した時、出来る限り状態をクリアにしたほうが、次回の実行に易しいです。
ただ、失敗のタイミングによって条件分岐でクリアの処理を仕込む必要がある場合、複雑になってしまうため、そもそものスクリプトの規模等を見直したほうがいい場合があります。

テストリソースの衝突は結構重要である。
並行実行で同じテストデータを使用する場合。この時、双方で共有するデータがお互いに変更を加えるため、validateをするときに影響を及ぼす。

例を以下に示す。
同じユーザーに対して、お気に入り登録・削除する処理を同時に実行された場合

このように、処理分散を目的に複数のjenkins等でtest automationを実行させるとき、テストデータの衝突を気にする必要がある。

十分なスペックのテスト環境として、以下のようなことを考慮する
- WEB アプリケーション側のサーバースペック
- クライアント側のスペック
- クライアント側のネットワークスペック(特にスマートフォンのように、無線で接続するようなケース)
環境が不安定だと、当然テストは失敗しやすいです

待つ処理は結構厄介である。
必要以上に長い時間を(例えば、想定される時間x 2 )設定する場合、失敗は発生しにくいでしょう。
ただ、その場合、scriptの実行時間が長くなってしまいます。
それは避けたほうが良い。
そのため、平均的な待ち時間 + ランダムな時間を設定することで、失敗がなかなか起きず、かつ実行時間が長くならないような工夫をする。

リトライの実装は、結構有効である。
例えば、ネットワークのタイムアウト等である。
ただ、実装はかなり難しいものになる。
なぜなら、単純にリトライすると、例えば更新処理などのページでは、アプリ側で2重処理をブロックする仕組みでエラーになりうるからである。
そのため、リトライが限られる場合がある。

11.Flexible trap

"Flexible trap"とは、"柔軟性のある実装による罠"の意味である。
test automationは書かれたとおりに実行する。そのため、ちょっとした前提が崩れるだけで失敗する。
例えば、ブラウザを立ち上げてログイン処理を行おうとしたとき、すでにログインされた状態だとtest automationは失敗する。
マニュアルテストの場合、ログインされている状態と気づいて、ログアウトする、もしくはログインの処理をスキップして実行すると、状態に応じて柔軟に処理を変えることができる。

"柔軟性のある実装"とは、このマニュアルテストのように、状態に応じてtest automationの処理を切り分けることである。
そうすることで、様々な状態が発生してもテストが失敗しないようになる。
一見、素晴らしい実装で、日々の実行で運用が楽になるように思えるが、問題も起きる。

1. false negativeの可能性
2. 何のテストをおこなってるか不明

"false negative"は、テストが失敗しているけどエラーとして検知されないことである。
それはなぜ起きるか?

お気に入り機能で、登録されているデータを全部消す機能を考える。

"Normal"は、前提としてお気に入りが登録されているテストユーザーを使う。
通常であれば、"全削除"ボタンをクリックして、お気に入りが全部削除されたことを確認し、正常終了する。
ただし、すでにお気に入りが全削除されていた場合、このスクリプトは失敗する。

"Flexible"は、前提がお気に入り有り無し両方ともサポートする実装。
お気に入りがあれば、全削除を実施し、なければ正常終了とする。

この "Flexible"では何が問題か?
それは、"全削除"の機能に注目するのではなく、"お気に入り登録したのにMyPageでお気に入りが表示されず、全削除ボタンが表示されない"という不具合を見逃してしまう(False Negative)。

そのため、Flexibleしすぎないように、テスト前提を setupで設定して進めることに心掛ける方がよい。

"何のテストをおこなってるか不明"は、Flexibleの延長である。
どうしてもIF条件で処理を分岐させて実装しないと、自動化スクリプトのメンテナンス上負担になる場合がある。
ただ、それでも条件分岐をたくさん組み込んだとしよう。

ここまでいろんなパターンを状態に応じて処理分岐をさせた場合、
テストを複数回実行するなかで、何のテストをしたのかがわからない。
また、何時すべてのテストパターンの実行がされるかがわからない。

このように、flexibleな実装は、運用上・保守上必要にはなるが、行き過ぎた実装は本来のテストの目的を逸し、テストが失敗しないような実装になりかねない。

Finaly

次は7月17日(金)頃配信予定です。
次は、Test Automation operationを執筆予定です

reference

back number