テストを自動化するのをやめ、自動テストを作ろう

 テストを自動化するのをやめ、自動テストを作ろう

July Tech Festa 2020 TrackB https://jtf2020.peatix.com/

Ea9506ab742ba01d1bea53af6f5649b7?s=128

tsuemura

July 25, 2020
Tweet

Transcript

  1. テストを⾃動化するのをやめ、 ⾃動テストを作ろう Takuya Suemura @ Autify, Inc.

  2. 末村 拓也 (すえむら たくや) Twitter: @tsueeemura Autify テスト⾃動化スペシャリスト 開発者 兼

    サポート 兼 エバンジェリスト 現場猫 → 底辺PHPer → QAエンジニア → 現職 CodeceptJS コントリビュータ SoftwareDesign誌 6〜8⽉号『はじめよう,⾼速 E2Eテスト』
  3. Autifyについて WebアプリのE2Eテスト⾃動化の ためのツール AIによるシナリオの⾃動修復 (セルフヒーリング) リアルデバイス & Dockerコンテ ナでの実⾏に対応 コーディング不要で

    誰でもすぐ使える https://autify.com
  4. 今⽇のテーマ

  5. テスト⾃動化

  6. テスト⾃動化をやめて、 ⾃動テストを作ろう

  7. テスト⾃動化 ≠ ⾃動テスト

  8. テスト⾃動化の成果物 ≠ ⾃動テスト

  9. ⼿動テストを素朴に⾃動化しても、 ⾃動テストにはならない

  10. 今⽇話すこと なぜテスト⾃動化は失敗しやすいのか ⼿動テストと、その⾃動化、そして⾃動テストはどう違うのか ⾃動テストとはどうあるべきか ⼿動テストの⾃動化に価値はないのか とくに断りがない限りはE2Eテストについての⾔及です (E2Eテスト: システム全てを統合した状態で主にUIからやるテスト)

  11. なぜテスト⾃動化は 失敗しやすいのか

  12. 本題に⼊る前にコンテキストの説明 E2Eテストとは テスト⾃動化とは

  13. E2Eテストとは ビルド済みのアプリケーションに対して Webブラウザやモバイル端末から 主にGUIを通してテストを実⾏すること システムテストと呼ばれたりもする QA(品質管理)とかテスターとかが⼿動でポチポチやることが多い ⼿動のものを「⼿動テスト」、⾃動のものを「E2Eテスト」と呼んだりする⼈ もいるが、今回は実⾏⼿段を問わず全てE2Eテストと呼称する

  14. よくある開発の流れ ローカルで開発 プルリクエストを出す メインブランチにマージ ステージングサーバにデプロイ E2Eテスト 問題がなければ本番にリリース

  15. テスト⾃動化とは 主に⼿動で⾏ってきたE2Eテストを⾃動化すること Selenium, Puppeteer, Cypress, TestCafe, Appiumなどを使う 主に省⼒化や⾼頻度化が⽬的 副次的に実⾏者によるバラツキの削減などもある テスト⼿順は⼿動テストのものを流⽤する

    開発の流れそのものは変えない
  16. Checking vs Exploring

  17. Checking vs Exploring

  18. テスト⾃動化が失敗する(機能しなくなる)よくあるパターン ⼿動で頑張ってたテストを⾃動化してみたはいいが……︖ 突然動かなくなる (メンテナンスコストが⾼い) アプリケーションは動いてるがテストは落ちる 不安定で成功したり失敗したりする 思ったより効果が出ない (費⽤対効果が⼩さい) テストしてないところでばかりバグが出る 早期発⾒に繋がらない

  19. ⼿動テストを⾃動化するとたくさんの観点が失われる # ログインページ ## ログインできる 1. URL /login にアクセスする 2.

    ユーザー名に takuya と⼊⼒する 3. パスワードに insecure と⼊⼒する 4. ログインボタン をクリックする 5. ホーム画⾯ が表⽰されることを確認
  20. describe('ログインページ', () => { it('ログインできる', () => { browser.get('/login') //

    URL /login にアクセスする $('#username').setValue('takuya') // ユーザー名に takuya と⼊⼒する $('#password').setValue('insecure') // パスワードに insecure と⼊⼒する $('a.btn.btn-primary').click() // ログインボタン をクリックする assert.equal(browser.url, '/home') // ホーム画⾯が表⽰されることを確認 }) }) ロケータ(要素探索のキー)がセマンティックじゃなくなった ユーザー名を⼊れるフィールドっぽいやつ → #username ログインボタンっぽいやつ → a.btn.btn-primary アサーション(検証)が弱くなった ホーム画⾯っぽいページ → /home というURLである
  21. assert.ok( $('a[href="https://yahoo.co.jp"]') .isExisting() ) CSSが読み込まれてないけど Aタグが存在するからヨシ︕

  22. なぜ⾃動化したテストだけが「腐る」のか︖ 実はユニットテストでも同じことは起きている 違いは開発サイクル ユニットテストは「開発の中で」実⾏・修正される ⾃動化したテストは「開発が終わってから」実⾏・修正される もともと⼿動テストがそういう流れでやってたことの名残 リリース直前にテストが壊れているのが分かった場合、壊れたままリリースする ことがある 結果、メンテナンスが後回しになってしまう これが「腐る」の正体

    実⾏頻度が⾼く、開発中も実⾏されるようになると、テストは腐りにくくなる
  23. 単純に頻度を⾼めればいいのか︖ 頻度を⾼める(例えば1回/⽇→10回/⽇)にしても問題は解決しない 回数ではなく実⾏環境の幅を増やさないといけない 例えば、もともとステージングだけで実⾏していたなら、それを開発環境や CI環境でも実⾏できるようにする ⼿動テストを単純に⾃動化しても、 前提条件 や 事前準備 は⾃動化されない

    特定の環境に依存したテストケースになってしまう 環境や特定のテストデータに依存している限り、開発サイクルに寄せることはで きない 依存している前提条件をクリアにし、どの環境でも実⾏できるテストにする
  24. (まとめ)テスト⾃動化が失敗してしまう理由 開発サイクルの中でテストが実⾏・メンテナンスされていない テストコードのアップデートが遅れ、製品に問題はないのに「E2Eテストだけ 失敗する」になりがち 実⾏タイミングが遅く、バグの早期発⾒に繋がらない 観点が不明瞭なままテストコードに落とし込んでしまう 「ホーム画⾯が表⽰されることを確認」→「URLが /home であることを確 認」のような不正確な翻訳が⽣まれる

    ⼈間がテストする場合にくらべ発⾒が少なくなってしまう
  25. テスト⾃動化と ⾃動テストの 違いとは︖

  26. ⾃動テストの⼀般的なイメージ コードで書かれる xUnitとかRSpecとか TDD・リファクタリング 安全な開発のためにやるもの (なんとなく)QAとかテスターがやるやつとはちょっと違う

  27. ⾃動テストと型検査、Linter ⾃動テスト: アプリケーションが期待した動きをしないとリリースできない 型検査: 型に不整合があるとビルドが通らない Linter: 不適切な書き⽅をすると警告が出る それぞれの対応する領域に対して強制⼒を持つ

  28. アプリケーションと⾃動テストの関係 どちらもプロダクトの⼀部 どちらも仕様を具現化したもの アプリケーションはそれ単体では意味をなさない 誰かに使われてはじめて価値を⽣み出す アプリケーションは振る舞いを具現化したもの ⾃動テストは使い⽅を具現化したもの ⾃動テストはアプリケーションを束縛する アプリケーションの特定の挙動に依存することでその挙動を束縛する 互いにコードとして書かれ、実⾏可能な形で記述されていることで強制⼒を

    発揮する
  29. ⾃動テストとは プロダクトの⼀部であり、同時に開発される 開発サイクルの中で実装される (テストフェーズの⾃動化ではない) アプリケーションの挙動に強く依存し、 アプリケーションをより強固にする 静的解析などと同様に頻繁に実⾏され、 仕様からの逸脱を常に防ぐ

  30. 素朴なテスト⾃動化は部分的な変化のみをもたらす - ⼿動テスト テスト⾃動化 ⾃動テスト 開発サイクル 開発とは別 開発とは別 開発と同時 頻度

    少 少 多 実⾏⼿順 あいまい・暗黙的 厳密・具体的 厳密・具体的 検証⽅法 発⾒的 保証的 保証的 太字は⾃動化によって変わってしまうもの ⾚字は⾃動化しても残り続けるもの
  31. おれたちが本当に 欲しかったものは︖

  32. None
  33. None
  34. None
  35. None
  36. None
  37. テスト⾃動化の動機 ⼈間からの脱却 単純作業からの解放 リソース不⾜の解決 属⼈化防⽌ 検証作業のバラツキを減らす ⾼速化・⾼頻度化 リリーススピードの向上 いつでもテスト リファクタリング

    上司のご意向
  38. (再掲)⼿動テストとテスト⾃動化、そして⾃動テストの違い - ⼿動テスト テスト⾃動化 ⾃動テスト 開発サイクル 開発とは別 開発とは別 開発と同時 頻度

    少 少 多 実⾏⼿順 あいまい・暗黙的 厳密・具体的 厳密・具体的 検証⽅法 発⾒的 保証的 保証的 太字は⾃動化によって変わってしまうもの ⾚字は⾃動化しても残り続けるもの
  39. なぜテスト⾃動化では ⾼速・⾼頻度が 実現されないのか

  40. ⾼頻度化に向けて(1) シナリオの最適化 ⼿動テスト向けに最適化された状態 あるテストで作られたデータを別のテストで再利⽤している 「新規作成」のシナリオで作ったデータを「更新」で再利⽤ 特定の環境にしか存在しないテスト⽤データを使っている

  41. ⾼頻度化に向けて(1) シナリオの最適化 ⾃動テスト向けに最適化する ⽬的︓CIでの実⾏や並列実⾏との相性を良くする 常に新しいデータを作成する GUIではなくAPIやコマンドで作成する 実⾏が他のテストに影響しないようにする 例えば、テストデータの作成時にランダムな(重複しない)⽂字列を使う 環境依存の箇所を排除する 環境変数を使う

  42. ⼿動テスト最適化 機能1 機能2 機能3 ログイン 機能1 ログイン 機能2 ログイン 機能3

    機能1の データ作成 機能1, 2の データ作成 ログイン ログアウト ログイン ログアウト ⾃動テスト最適化 テスト⽤の ユーザー作成 事前準備 実⾏ 事後処理 機能1の データ作成 テストデータの 削除
  43. ⾃動テストらしいテスト⾃動化 開発中も含めさまざまな環境でテストされている ⾼頻度(理想はコミットorプッシュごと)に実⾏され不具合を防ぐ 安定性が⾼い 他のテストシナリオからの影響を受けない 何度も、同時に実⾏されても問題ない(冪等性がある) テストシナリオが短く保たれている テスト観点以外の操作はAPIやコマンド(サーバサイドスクリプト)で⾏う

  44. HAPPY END! (?)

  45. ⾼頻度は実現できたが、⼈間からは脱却できたか︖ ⼈間からの脱却 ← こっちがまだ 単純作業からの解放 リソース不⾜の解決 属⼈化防⽌ 検証作業のバラツキを減らす ⾼速化・⾼頻度化 リリーススピードの向上

    いつでもテスト リファクタリング 上司のご意向
  46. 参考: テスト⾃動化の8原則 1. ⼿動テストはなくならない 2. ⼿動でおこなって効果のないテストを⾃動化しても無駄である 3. ⾃動テストは書いたことしかテストしない 4. テスト⾃動化の効⽤はコスト削減だけではない

    5. ⾃動テストシステムの開発は継続的におこなうものである 6. ⾃動化検討はプロジェクト初期から 7. ⾃動テストで新種のバグが⾒つかることは稀である 8. テスト結果分析という新たなタスクが⽣まれる https://sites.google.com/site/testautomationresearch/test_automation_principle
  47. 参考: テスト⾃動化の8原則 3. ⾃動テストは書いたことしかテストしない ⼈間による⼿動テストは、テストケースの記述に対して驚くほど広範な要素を暗 黙的にテストしている。これに対し、操作、合否判定を厳密に記述する必要があ る⾃動テストにおいては、おのずと視野は「記述された様に」限定される。ユー ザ名とパスワードを⼊⼒してログインする、といったテストが⾃動化されていた として、その⾃動テストは仮にログイン画⾯に表⽰されているロゴが競合他社の ものであったとしても、それに気づくことはない。

    (太字は発表者によるもの) https://sites.google.com/site/testautomationresearch/test_automation_principle
  48. アサーション地獄もまた「素朴な⾃動化」の⼀つ

  49. 再掲 assert.ok( $('a[href="https://yahoo.co.jp"]') .isExisting() ) CSSが読み込まれてないけど Aタグが存在するからヨシ︕

  50. 参考: テスト⾃動化の8原則 7. ⾃動テストで新種のバグが⾒つかることは稀である 運⽤に乗った⾃動テストは基本的に「枯れた」テストケースを対象とするため、 ほとんどの種類のバグはテストケースを枯らす過程、あるいは⾃動テストを実装 する過程で既に⼈間によって発⾒されているはずである。 多くの運⽤に乗った⾃ 動テストの意義は「⼀度動いたはずの機能がうっかり壊れる」ことを最速で発⾒ することにある。

    ただし、⼿順が同じでデータの種類が膨⼤なテストを⾃動化す る場合、ファジング、テストパターンを有機的に⽣成できるAPIレイヤのテスト、 ブラウザやRDBなどのバージョンアップの影響を受けていないことを確認するテ ストなど、いくつかの例外もある。 (太字は発表者によるもの)
  51. (再掲)テスト⾃動化が失敗するよくあるパターン ⼿動で頑張ってたテストを⾃動化してみたはいいが……︖ 突然動かなくなる (メンテナンスコストが⾼い) アプリケーションは動いてるがテストは落ちる 不安定で成功したり失敗したりする 思ったより効果が出ない (費⽤対効果が⼩さい) テストしてないところでばかりバグが出る 早期発⾒に繋がらない

  52. 開発サイクル寄りのかっちりしたテストとは 別のアプローチが必要

  53. ふんわり

  54. 「ふんわり ≒ ⼿動テストよりの」⾃動テスト - ⼿動(ふんわり)テスト テスト⾃動化 ⾃動(かっちり)テスト 開発サイクル 開発とは別 開発とは別

    開発と同時 頻度 少 少 多 実⾏⼿順 あいまい・暗黙的 厳密・具体的 厳密・具体的 検証⽅法 発⾒的 保証的 保証的
  55. 「ふんわり」が必要な理由 「かっちり」では⾒落としてしまうものがある 環境依存のデータに依存するものを検知できない 例)⼤量の関連データを持ったユーザーのみ正常に動作しない アサーションを書いてないものを検知できない 明らかにおかしいけど⼿順書に書かれてないからヨシ︕ 特にレイアウト崩れとかは弱い 全部 getComputedStyle でやっちゃう︖

  56. 「ふんわり」が必要な理由 「かっちり」はそもそもE2Eらしくない かっちりしたテストで検証するのはクリーンで焦点を絞ったテスト E2Eはそもそもダーティでリアルな状況下でのテストが⽬的のはず ステージングや本番にしかないデータ ブラウザやデバイスなどの実⾏環境 リアルな環境で「正しそうに」動くことを確認するものが欲しい

  57. 「ふんわり ≒ ⼿動テストより」 の⾃動テストは実現可能か︖

  58. ふんわりしたロケータ かっちりテストとは異なり、開発サイクルの中でメンテされるとは限らないので ふんわり≒宣⾔的なロケーティングが必要 // これはよくない $('#username').click() // これは次善の策 $('[data-test=username]').click() //

    こう書けると良さそう $('ユーザー名').click()
  59. ふんわりしたロケータ(1) セマンティックロケータ ⽂⾔や構造による「意味のある」ロケータ #username ではなく ユーザー名 のように表⽰されている⽂⾔で指定 例えばinputならラベルやプレースホルダを使う xxという⽂⾔を持つモーダルの中のyyというボタン のようなUI構造で指定

    // CodeceptJSでは⽂⾔や構造による指定をサポートしている I.click('ユーザー名') // 「本当に送信しますか︖」という⽂⾔のあるモーダルの中から within(locate('.modal'.withText('送信先は間違いありませんか︖'), () => { // 「はい」と「送信」をクリック I.click('はい') I.click('送信') })
  60. ID: not matched class: matched alter text: matched coodinate: not

    matched image source: matched .... Confidence: 80% ふんわりしたロケータ(2) AIによる要素探索 (マルチロケータ、 セルフヒーリング) 複数のロケータで複合的に探索 ⾒つかった要素の特徴でシナリ オをアップデート 開発サイクルとテストのサ イクルのズレを吸収
  61. ふんわりした検証 アサーション地獄を回避したい 全ての検証項⽬を地道に定義するのはメンテナンス地獄にも繋がる ⼈間がパッと⾒て分かるレベルのエラーを(定義せずに)回避したい 表⽰されるべきものが表⽰されていない レイアウトが崩れている

  62. ふんわりした検証 画像⽐較(ビジュアルリグレッション) テスト実⾏ごとのスクリーンショットを⽐較する スタイル崩れなどの検出に有効 ⽐較から除外する箇所の定義が別途必要 広告 検索結果 撮影時の座標がズレると全てが終わる 位置ずれ補正 Awesome

    Visual Regression Testing: 画像⽐較テストツールのリンク集 https://github.com/mojoaxel/awesome-regression-testing_
  63. ふんわりした検証 その他考えうる施策 ページパフォーマンス、エラー監視 デッドリンク検知 ⾃然⾔語解析 テキストの意味が⼤幅に変わっていないか ⽂法の誤り etc...

  64. かっちりとふんわり どっちがいいの︖

  65. テストを「網のように」考える バグはなるべく上層でキャッチするようにしつつ、下にも網を広げる ユニットテスト 統合テスト APIテスト UIコンポーネントテスト かっちりしたE2Eテスト ふんわりしたE2Eテスト ⼿動での探索的テスト

  66. テストタイプによる使い分け例 かっちりテスト向け 機能テスト 回帰テスト ふんわりテスト向け 互換性(クロスブラウザ・マルチデバイス)テスト ユースケーステスト スモークテスト

  67. 今⽇伝えたかったこと ⼿動テストを素朴に⾃動化しても、⾃動テストにはならない 素朴なテスト⾃動化はどっちつかずのものになってしまう 新規バグは⾒つからず、そのくせメンテ⼯数はガッツリ持っていく ⾃動テストらしい具体性をもったかっちりした⾃動テストと、⼿動テストのよう にファジーなふんわりした⾃動テストというアプローチがある テスト⾃動化をゴールにするのではなく、エントリーポイントとして使い、さら に発展させてほしい

  68. Enjoy Testing! spatial.chatの H1 で僕と握⼿︕