JaSST nano #7 Test Automation Operation (2021/12/21)

# Outline

2021/12/21 JaSST nano #7 にて発表する機会をいただきました。
そこで発表した内容を記事としました。

https://jasst-nano.connpass.com/event/232441/

<A HREF="https://www.slideshare.net/SadaakiEmura/20211221-jasst-nanotest-automation-operation">![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/91029313-75b4-c38a-2c14-15262c3869f5.png)</A>


# Background

テスト自動化は、使われる目的によって大きく運用方法が異なります。
そのため、我々の部署のテスト自動化の目的をまず紹介します。

まず、部署ですが開発とQAが独立した組織になっています。
我々の部署QAは、複数の開発部署の品質検証する立場にあります。
また、QAのなかでもマニュアルテストとテスト自動化をするグループが分かれています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/9bd22488-aee4-c48b-d492-1a424b60b6a0.png)

QAは、テストとしてEnd to End (E2E)のユーザー視点のテストに特化しています。
そのため、UnitやIntegration Testは開発がresponsibilityを持ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/7da9f239-35d2-7faa-26a7-1d066cda9ce6.png)

テスト自動化のグループでは、E2Eのテストの自動化を担当します。
このE2Eのテスト自動化を毎日実行させることで、早期に不具合等を検出するようにしています。


# What do you think test automation?

まず、「テスト自動化」をどのように想像しているでしょうか？
理想像を以下のように思っている人は、少なからずいると思います。

- Scriptはずっと使いまわせる（例えば、ｘ回実行すれば元が取れる理論）
- テスト自動化は実施→成功を繰り返し、バグがあるときだけ、テストが失敗してエンジニアに知らせてくれる
- テスト自動化がスピーディに勝手に対応してくれるので、定時には普通に帰れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/3797db8e-4e24-2604-fade-aa3281e7579f.png)


ただ、実際問題として

- 仕様はよく変わる。そのため、Scriptの使いまわしはできない。
- E2Eテスト自動化は、バグ以外でよく失敗する
- テスト自動化はずっと使っていると、なぜかどんどん遅くなっていく。そのため、feedbackが遅くなる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/2130b2f6-4856-644d-dee1-3586c7bcaea5.png)

# How to handle these situation

## 仕様はよく変わる

テスト自動化でよく言われる？のが

```
仕様（UI)の変更するところにテスト自動化を適用する。
```

である。しかし、これは正しいのだろうか？
テスト自動化のフェーズに依存すると思います。
テスト自動化の初期フェーズでは、まず自動化を早く成功させることが1番の目的にあるとおもいます。
そのため、仕様がころころ変更するところをターゲットにすると、テスト自動化プロジェクトがなかなか完了せず、途中でなえてしまうかもしれません。
そのため、初期フェーズでは正しいと思います。

ただ、ある程度成熟してきたときに、これに従ってテスト自動化するべきだろうか？
むしろ、われわれのように、頻繁にリリースを行うWEBサービスにおいて、重要でかつ仕様が変わる部分に関してテスト自動化を適用し、品質担保かつリリースサイクルを早める取り組みをすべきだと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/74713b2d-8de0-d8f5-5060-49e919b400fa.png)

このフェーズになると、「テスト自動化は常に仕様に追従させる」という運用を考えないといけません。

まず、プロジェクトの規模に応じてテスト自動化のスコープを考える必要があります。
下図のように、１～２週間のプロジェクトの場合、テスト開始からリリースまでの期間が限られます。
priorityを考えると、既存機能のテスト自動化を最優先して対応し、リリース前までにテスト自動化が最新の仕様にあわせて、テスト実施する必要があります。
余裕があればいいですが、新規機能で新規にテスト自動化を作成する場合は、priorityを下げざるを得ません。
たいていの場合は、リソース次第で次の開発プロジェクトに準備できていればいいのではないかという感覚です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/3fa0ecc0-adf5-887e-a70b-ced7cf930e3c.png)

また、先に説明した通り、マニュアルテストとテスト自動化の担当は異なります。
開発プロジェクトに対するテストは主にマニュアルテストの担当者がleadします。
そのひとたちと、プロジェクトの情報などを密にやりとりをしてともに進めていくことが重要になります。
「お互いになにをやってるのかわからないけど品質が担保されている」といったようにならないようにする必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/9aae5f75-3f78-89b5-d9bc-e1f2aed82720.png)


## E2E テスト自動化はfragile

E2Eテスト自動化はよく失敗します。
しかもバグ以外の原因でよく失敗します。
つまり、「テスト自動化はよく落ちる。そして調査に時間をかける」運用が発生します。

この調査がまた大変である。
「<A HREF="https://sites.google.com/site/testautomationresearch/test_automation_principle">テスト自動化の8原則</A>」のひとつに以下のものあります。

```
テスト結果分析という新たなタスクが生まれる
```

これはなにかというと、下図のようにマニュアルとテスト自動化のバグ発見までのフローを比較するとよくわかる。

マニュアルテストの場合、テスト作業は発生します。だが、テスト作業の過程でバグを発見するため、すぐにバグであることが確認でき、かつ再現手順、どのSTEPで失敗することがわかります。
よって、開発者へのバグレポートをすぐに作成することができます。

一方、テスト自動化の場合、普段JENKINSが勝手にテストをやってくれています。
JENKINSはテスト失敗したことだけを通知してくれます。そこから、テスト自動化エンジニアの大変な作業が発生します。
まず失敗レポートを確認し、なぜ、どこで失敗したのかを確認します。
テスト自動化はfragileです。バグの可能性があれば、バグではない可能性もあります。その切り分けもする必要があります。
レポートを見るだけでわからないときもあります。たとえば、テスト自動化は画面上のobjectを特定して（例えばXPath等）実行しているため、そのpathが変更したことによる問題かもしれません。その場合、実際に同じテストを自分のlocal PCなどで実行し、objectのpathがただしいのか否かを確認したりすることも発生します。
最終的に、バグと特定できればバグレポートを作成します。そうでない場合は一時的に失敗した等なので、JENKINSを再実行し成功するを確認します。

このような流れで、テスト自動化が失敗したときの結果分析に非常に時間をかけます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/4dbbd135-eb08-3279-8710-9154904571a7.png)

また、残念なことにテスト自動化はfragile、バグで失敗する比率が非常に低いということもわかっています。（あくまで、われわれのテスト自動化における結果です！）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/f07c7cb0-52c6-f5f0-d914-90cb1ca9e59b.png)

バグの検知のシェアが大ききればいい傾向ですが、実際は約5%。
temporary unstable、環境不安定によるテスト自動化失敗が74%を占めています。
つまり、あまり意味のなさない結果に対して結果分析は全然生産的ではありません。

われわれは、これらの作業を低減させるために、いろいろな取り組みをしました。
いくつかあるなかで、２つとりあげます。

ひとつは、調査を速やかにできるように、関連する情報を集約させ調査開始までの時間短縮を行いました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/03119bd5-177a-8abd-612e-b64cb4610caa.png)

もうひとつは、先に示した、temporary unstableであろうテスト結果を自動で抜き出して、それらはテスト再実行したら成功するであろうということで、自動で再実施させる。
これにより、本来調査すべき不具合に絞り込む工夫を行いました。
※くわしくは JaSST'21 Tokyoで発表した資料をご覧ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/ad68dcb1-6c60-b929-e0cc-711f6b0304f9.png)



## テストはどんどん遅くなる

テスト自動化は、アプリケーションと一緒でケースバイケースですが、performanceがわるくなっていく。
悪くなる原因はいろいろあると思います。

例えば、テストを繰り返すことでテストデータがどんどん蓄積され、それによるアプリケーションのパフォーマンス劣化。
もしくは、マイページ等でそのテストデータが存在することをvalidationとする場合、それを大量のテストデータの中から探すのに時間がかかってしまうパフォーマンス劣化。
単純にスクリプトが肥大化してしまい、テスト自動化のscriptのパフォーマンス劣化。

このパフォーマンス劣化は、テストのfeedback speedにも当然影響してしまう。
そのため、その対象のテストを探し、調査・改善する必要が発生する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/542d0235-5a23-849b-fb06-f72b55c13f21.png)

具体的な改善策は、サービス、テスト自動化のプラットフォーム等に依存するため、今回割愛します。
今回は、performanceに影響を与える問題児をどうやって早く見つけ出すかの取り組みに関して紹介します。


一つ目は、jenkinsのscheduleを監視する仕組みです
最初に紹介した通り、すべてのテストを毎日実行しています。
そのため、このscheduleが適切に設定、テストが稼働しているかを確認する必要があります。
各時間に対してtest実行に何時間使われているか、どれだけのテストが登録されているか、そして超過しているものがないかを可視化します。

二つ目として、各テストのperformanceを監視する仕組みです
- テストの実行履歴
- テストの実行平均時間
- テストの実行時間の履歴
を可視化し、かつ一定の条件で絞り込む機能を有しています。

これにより、問題児のテストをすぐに割り出し、定期的な改修・改善を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/2e962fe9-7b10-255e-02b6-94f6f3d4a763.png)


# Finally

テスト自動化はフェーズによりますが、以上のように必ず運用が重要になってきます。

- テスト自動化は常に仕様に追従させる
- テスト自動化はよく落ちる。調査に時間をかける
- テスト自動化のパフォーマンスを監視、改善する

テスト自動化の目的によって求められる運用内容はことなってきます。
しかし、このような運用を続けないと、テスト自動化はいずれ使えなくなる遺物になってしまうでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/fedc5856-a7a9-5f2e-9bee-7b7d7a640159.png)