AutifyによるE2Eテストの自動化


## 自己紹介
- 開発経験は4年ほどです。
- Go,TypesScript, Rubyを普段書いてます。
- フロント、サーバ、インフラの経験があります。
- [github](https://github.com/koukikitamura)です。


## ソフトウェアテストの必要性
私たちの身の回りでスマートフォン、パソコン、家電製品、自動車など様々な箇所でソフトウェアが使われています。ソフトウェアは生活に必要不可欠なものとなっており、私たちはソフトウェアが正常に動作することを当たり前と考えています。したがって、ソフトウェアが正常に動作しないとソフトウェアを開発した会社の信用、時間、お金を失ってしまう恐れがあります。

## ソフトウェアテストの自動化の必要性
ソフトウェアテストとは実装したソフトウェアを実際に動作させ不具合を検出する行為です。不具合を全て検出するには全ての条件でソフトウェアを動作させる必要がありますが、実際の現場では人的リソースと時間的リソースは限られているので全ての条件を検証することは難しいです。このような背景からソフトウェアテストの自動化の必要性が高まっています。

## ソフトウェアテストの種類
テストの種類には単体テスト、統合テスト、システムテスト、受け入れテストがあります。
単体テストとはプログラムの構成単位(関数、クラス、モジュール、パッケージなど)に対するテストです。通常は開発者がテストをします。統合テストはシステムの構成単位(APIサーバ、マイクロービス、フロント）に対するテストです。通常は開発者がテストします。システムテストは実際のユーザと同じ使い方でシステムを操作してテストを行います。開発者も動作確認はしますが、複雑なテスト設計とシステムの品質に対する保証は開発者とは別のQAエンジニアが行うのが一般的です。受託開発のシステムだとシステムテスト終了後に納品先の会社で発注したシステムが正常に動作するかを確認する受入テストもあります。

単体テストと統合テストは多くのチームで自動化されておりCI/CDの中でテストコードが実行されるうようになっています。一方、システムテストを自動化するツール(Selenium、Puppetter、Cypressなど)は存在するものの継続的にシステムテストの自動化が上手く機能しているチームは少ないはずです。


| テストの種類 |  テスト担当者 | 
| -- | -- |
| 単体テスト | 開発者 |
| 統合テスト | 開発者 |
| システムテスト| QA担当者 |
| 受入テスト | 納品先の会社 | 


## システムテストのテストケース
多くのチームではエンジニアチームとは別にQAチームが存在しており、エンジニアがテストケースを設計してシステムテストを行うことはないはずです。エンジニアにとってシステムテストのイメージはUIを操作して機能を一通り触ってシステムの妥当性を検証するという漠然としたイメージしか持っていないことも多いはずです。それぞれの画面で様々な入力値のパターンを一つずつ決めて、動作結果が期待通りかを丁寧に検証してます。

## 自動化すべきテストケース
自動システムテストの役割は新機能に対する品質保証ではなく、既存の機能に対するデグレーションの確認です。自動化の目的は工数削減なので自動化により工数削減になるテストケースを自動化する必要があります。自動化して工数削減するテストケースは以下の不等式を満たす必要があります。

```
一回あたりの手動での実施コスト x 実施回数 > 自動化の導入コスト + 自動化のメンテコスト
```

この式の(左辺) - (右辺)が削減工数となります。変数が４つありますが、実施回数以外はテストケースによって差は小さいので定数とみなします。つまり工数削減は実施するテストの実施回数にのみ依存します。新機能のテストはその機能のリリース前には重点的に行われますが、それ以降の実施回数は少なくなります。リグレッションテストはリリースの際に定期的に実行されるので工数削減が見込まれます。アジャイル開発の場合は、開発→テスト→リリースのサイクルを繰り返すのでシステムテストの自動化と親和性が高いです。システムテストは全てを自動化するものではなく、多くても全体のテストケースの30%ほどになります。人間による手動のテストがなくなることはありません。

リグレッションテストの他にも以下のものは自動化を検討する余地があります。工数削減に繋がるか検討しながら少しずつ自動化しましょう。
- プロダクトの根幹の重点的なテスト
- 基本機能の広く浅いテスト
- 不安定でバグを多く出した機能のテスト
- 工数が足りなくて実施できなかったテスト

## システムテストの自動化に使うツール
システムテストの自動化のツールは様々なものがありますが、エンジニア以外でも簡単にテストケースの自動化とメンテナンスができるSaasである[Autify](https://autify.com/) を使います。

Autifyはスクリプトを書く必要はなくブラウザでの操作を自動で記録して、テストケースを作成することができます。ブラウザの操作の記録にはChrome Extensionを使います。レコーディング画面にurlを入力すると、録画用に新しいwindowが開かれます。

![recording_start_scren.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216120/0390bae6-34f9-8a39-3b58-c74277644cd7.png)



テストしたい操作を新しいwindowで行い、左下の保存ボタンを押すとテストケースを保存することができます。

![recodding_menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216120/aacda9b9-7a53-70a4-6bb1-495e902689c6.png)

Autifyには４つの概念があります。

- シナリオ
- ステップグループ
- テストプラン
- テスト結果

シナリオは１つのテストケースでテスト実行の最小単位です。アプリケーションにログインして画像を投稿、他のユーザへメッセージ送信などが一つのシナリオに相当します。シナリオは複数のステップで構成されます。ボタンを押す、URLの遷移などアクションでシナリオは各ステップに分かれます。


![scenaio_detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216120/85923e17-294a-ddd9-9f14-8f2865b78c67.png)

ステップグループはシナリオの一部を共通化することができます。ただし、シナリオの冒頭部分のみという制約がああります。

テストプランはシナリオをグループ化して複数のテストを実行することができます。複数の実行環境でテストプランを実行することもできます。またテストプランを定期実行することもできます。

![test_plan_detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216120/d6f4d22a-f17b-6546-9485-011c6bb8731e.png)!




テスト結果はシナリオやテストプランの実行結果です。どこで失敗したかを確認することができます。

## 自動システムをCI/CDに組み込む
リリースがGithub ActionsのDeployという名前のworkflowで行われていると仮定します。Deployのworkflowが終了したらシステムテストのworkflowが開始されるようにします。テスト結果を見て成功したか失敗したかをslackで通知したいので、Autifyのテストプランが完了するのを確認する必要があります。そのためのCLIとして[autify-cli](https://github.com/koukikitamura/autify-cli)を使います。また、Autifyのslackの通知機能もありますが、テストプランごとに分けれるようにGithub Actionsの中で通知するようにしました。

```e2e_test.yaml
name: e2e-test

on:
  workflow_run:
    workflows:
      - Deploy
    types:
      - completed

jobs:
  autify:
    name: E2E Test
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [12.x]

    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      - name: Check out source code
        uses: actions/checkout@v1
      - name: Install Autify CLI
        run: |
          curl -LSfs https://raw.githubusercontent.com/koukikitamura/autify-cli/main/scripts/install.sh | \
            sudo sh -s -- \
              --git koukikitamura/autify-cli \
              --target autify-cli_linux_x86_64 \
              --to /usr/local/bin
      - name: Run Autify
        run: |
          response=$(atf run --project-id=${AUTIFY_PROJECT_ID} --plan-id=${AUTIFY_TEST_PLAN_ID} --spinner=false)
          test_result_id=$(jq '.id' <<< "${response}")
          status=$(jq -r '.status' <<< "${response}")

          echo "TEST_RESULT_ID=${test_result_id}" >> $GITHUB_ENV
          echo "TEST_RESULT_STATUS=${status}" >> $GITHUB_ENV
        env:
          AUTIFY_PERSONAL_ACCESS_TOKEN: ${{ secrets.AUTIFY_PERSONAL_ACCESS_TOKEN }}
          AUTIFY_PROJECT_ID: ${{ secrets.AUTIFY_PROJECT_ID }}
          AUTIFY_TEST_PLAN_ID: 99999
      - name: Notify Slack
        run: |
          .github/workflows/notify_slack.sh "E2E Test has finished. Result is ${TEST_RESULT_STATUS}. \`https://app.autify.com/projects/${AUTIFY_PROJECT_ID}/results/${TEST_RESULT_ID}\`"
        env:
          AUTIFY_PROJECT_ID: ${{ secrets.AUTIFY_PROJECT_ID }}
```

## システムテストの自動化で失敗するケース
システムテストの自動化が失敗する代表的なケースは以下のようなものがあるので、気を付けましょう。

- 自動化担当者がテスト技術について知らない
- 工数削減にならない箇所を自動化した
- 自動テストのメンテナンスの工数が大きい
- 自動化することが目的になっている

自動テストはリグレッションの確認が目的で、品質保証のための手動テストがなくなることは絶対にありません。