Outline
テスト自動化の1つのテストケース、テストスイートの作り方に関して説明します。
T-DASHのタグを入れていますが、どんなテスト自動化ツールを使っても概念は一緒です。
例を出すにあたって、T-DASHを使ってるだけです。
Terminology
テストケース、テストスイートのコンテキストを合わせるために解説します。
テストケース
一連の操作・検証のSTEPの集合をテストケースと呼びます。
下図例では、「トップページからログインを行い、ログインされることを検証する」ことが一つのテストケースになります。
STEPの途中で処理が失敗した場合、処理が中断します。
尚、中断した場合、ブラウザは開いた状態で中断した画面のままになります。
※T-DASHはsetup teardownがないため、上記の動きになります。
テストスイート
複数のテストケースの集合をテストスイートと呼びます。
下図例では、1つのテストスイートに3つのテストケースが含まれています。
テストケースが失敗した場合、次のテストケースに移って実行を継続します。
なぜ、テストケース、テストスイートの作り方が重要か?
テスト自動化のテストケースを作成するにあたって、運用を考えた実装をする必要があります。
その理由として、以下のようなことがあげられます。
- 一つのテストケースの実行時間が長いと終わるまで待たされる
- 1つのテストケースの中の一部(サブセット)だけをテストしたい時がある
- 依存シナリオがあり、そちらのテストを先に実行しないといけない
- 途中でテスト失敗し、再実行しようとしたら、成功したところを改めて実行するため、運用の時間が長くなる
- 途中でテスト失敗すると、それ以降のテストがすべて失敗し、その失敗処理の実行時間が無駄になる
テストケースの最適化の考え方
ここからは、テストケース(シナリオ)を最適にする考え方を説明します。
1つテストケースは最小限のテスト目的に
一つのテストケースは最小限のテストに絞り込むことをお勧めします。
望ましくないテスト
- ログインする
- 検索サイトから商品を探し、検索結果を検証する
- 検索結果から商品を選択し、お気に入り追加する
- マイページからお気に入り登録されていることを検証する
- お気に入りから、対象の商品のページに遷移する
- 対象商品を購入する
- マイページに遷移して、購入履歴で対象商品が購入されていることを確認する
いかがでしょうか?
このテストシナリオでは、大きく以下のようなテスト目的でテストされています
- ログイン機能の検証
- 検索機能の検証
- お気に入り登録の検証
- 商品購入の検証
つまり、1つのテストケースを実行すると複数のテスト目的が検証されます。
しかし、以下のような課題が生まれます。
- 商品購入の機能検証だけの検証を行いたいが、それ以外のテストも実行される
- 検索機能に不具合があるとき、それ以外の機能検証、例えば商品購入の機能検証ができない
- 商品購入の自動化スクリプトに問題があり、そのスクリプト修正・検証するのに、毎回正常に動く機能(検索、お気に入り等)を実行する必要がある
- 一つのテスト実行時間が長い
- 実行結果をリスト表示している場合(Jenkins等)、どの機能が失敗(不具合がある)のかがわかりにくい
このように、1つのテストケースに複数のテスト目的を持たせると、運用上、特にテスト実行が失敗した時、不都合が発生する。
望ましいテストケース分割
最小限のテスト目的に分割し、以下の4つのテストケースにした例を示す。
テストケース1 : ログイン
- ログインして、マイページでログインされたことを検証する
テストケース2 : 検索
- 検索サイトから商品を探し、検索結果を検証する
テストケース3 : お気に入り
- ログインする
- 指定した商品ページでお気に入り追加する
- マイページからお気に入り登録されていることを検証する
テストケース4 : 商品購入
- ログインする
- 対象商品を購入する
- マイページに遷移して、購入履歴で対象商品が購入されていることを確認する
ログインの検証は、単体と、テストケース3、4のように複合していると意見があるかもしれません。
しかし、テストケース3,4はログインをしないと検証できない機能なので、含める必要があります。
ただし、ログインのステップだけでログインが正しくされたことを検証していません。
一方、テストケース1は、ログインがされたことを会員情報の突合せで機能検証させます。
このように、1つのテストケースに最小限のテスト目的を持たせることで、早いテスト実行と、絞り込んだテスト検証を行えるようになります。
依存しないテストケース
1つのテストケース単独で、テストを完結できるようにする考え方です。
テストケースを繰り返し実施できる特徴も持ちます。
テストを細分化しすぎて、1つのテストを行うために複数のテストケースを実行する必要がある場合、テストケースの管理が煩雑になります。
極端な例は、以下です
テストスイート
テストケース1 : ブラウザopen
テストケース2 : ログイン
テストケース3 : お気に入り登録
テストケース4 : マイページに遷移して、お気に入り登録されていることを検証
テストケース5 : ブラウザclose
画面や機能で細分化されています。
ここで起きる課題として、以下のようなことが考えられます。
- テストケース数が膨大化する
- テストスイートを実行して、途中のテストケースが失敗しても継続して次のテストケースが実行される。しかし、後続するテストケースは必ず失敗するため、テストリソースが無駄になる
このような課題が起きるため、テストケース単体でテスト目的が完了するように、また前のテストケースに依存しない実装にすることが望ましい。
依存するテストケース
先ほど依存しないテストケースを実装することを説明しました。
ただ、それとは真逆の考え方を持つ必要があるときもある。
特にテストデータに依存するテストケースの場合である。
依存するテストを分割する例と理由
次のテストを例として考えます。
新規ユーザーを作成した時、初めてマイページにアクセスすると、チュートリアルページが表示される。
- ユーザーAを新規会員登録を行う(尚、emailが同じユーザーは作成できない)
- マイページに遷移して、チュートリアルが表示されることを検証する
- ユーザーAを退会処理する
このテストシナリオは、依存しないテストケースの考えから、3つのテスト目的を含んでいます。
新規会員登録機能、初めてのユーザーはチュートリアルが表示される機能、会員退会機能。
理由は、このテストを繰り返し実施できるようにするため、作った会員データを削除する必要があるからです。
ただし、このテストケースを一つにはしません。下図のように3つのテストケースに分けたままにします。
なぜならば、途中でテストが失敗した時に、テストデータを復旧しやすいからです。
例をあげましょう。例えば、会員登録は成功したが、マイページで初めての人のチュートリアルが表示される検証でバグが発生したとします。
この時、バグが解消して再度最初からテスト実行したらどうなるでしょうか?二度とテストは成功しません。
それは、すでにユーザーが存在しており、同じemailのユーザーを作成できないため、新規会員登録で失敗するからです。
運用上、ユーザーAを手で削除すればいいですが、その場合工数がもったいないです。
3番目のテスト、ユーザーAを退会処理するをそのまま実行すれば、簡単にテストデータを復旧(クリーニング)することができます。
依存するテストを分割したときの実行方法
この場合、テストスイートに複数のテストケースをそろえます。
ただ、依存しないテストケースで説明したように、先行するテストケースが失敗すると、後続のテストケースは失敗します。(会員登録で失敗すると、マイページの検証、退会処理ができないため)
残念ながら、T-DASHにはテストケースが失敗した時、後続するテストケースの実行可否を設定できない。(Ranorexなどは、選択できます。下図が設定例)
このように、一連のテストケースをセットで実施させる(依存テスト)、途中でテストケースが失敗した場合、後続するテストは中断させる、この2つの条件を満たす方法として、Pipelineがある。
下図が、JenkinsでPipelineを組んだ例になる。
Step1、2、3と順に実行するが、途中で失敗した場合、そこでPipelineの処理を終了する。