📕

テスト自動化実践ガイドは目的も実践もほしい情報が揃っていて、まさにガイドでした

2024/08/04に公開

こんにちは。ダイの大冒険ガチ勢のbun913と申します。

みなさんはテスト自動化を推進していますか?

私は職責上SDET(Software Development Engineer in Test)として、「どんなメリットを受けたいからこういうテストレベルで、こういうことをやっていきましょう」「このテストはこのレベルで保証したテストをしてくれるとありがたいです」というコミュニケーションを取る必要が求められます。

例えばどんどんシフトレフトを進めていくにしても、当然E2Eテストでしか得られない栄養(安心感)があるので、そこも含めて「じゃあどんなことを自動化するのかな」「単体テストとは被るけどいいかな」などと思いを馳せることがよくあります。

そんな中、以下の書籍「テスト自動化実践ガイド 継続的にWebアプリケーションを改善するための知識と技法」を読んでみました。

https://www.shoeisha.co.jp/book/detail/9784798172354

結果として以下のような嬉しみポイントが詰まったとても良い書籍だと思いました。

  • 開発を継続的に支える自動テストとはどんなものか?
  • それらはどのように実行されていくべきか?
  • 具体的にツールを活用してどのように書いていけばいいのか?
    • CodeceptJS を活用されていますが、考え方は他のテストフレームワークやツールに流用できると思います

とはいえ書籍の内容を事細かに記してネタバレするのは極力避けつつ、私が特に印象に残った部分を軽く紹介したいと思います。

第1章 テストの目的

この章では「開発を支える自動テスト」とはどんなものか?素朴にテストを自動化したものとはどう違うのか?といったことが自動テストの目的とともに説明されています。

著書が以前に登壇された際の以下の資料においても、「手動テストを素朴に自動化しても、自動テストにはならない」といったワードの意味がわかりやすく説明されていますのでぜひご覧ください。

以下の表は上記発表資料中に出てくるものですが、これに似た表が書籍中にもあり、開発を支えるための自動テストとはどのようなものか?ということがわかりやすく説明されていました。

TestPurposeTable
テストを自動化するのをやめ、自動テストを作ろう より引用

  • 例えば機能的に受け入れ基準を満たしているか、といった観点での保証的かつ手順がはっきりとしているテストは自動化に適している
  • 一方でユーザビリティのテストなども含む探索的なテストは無理に自動化を目指すのではなく、依然として経験を持つ人が効率的に行うといった考えができるのかな。と受け取りました。

第2章 開発を支える自動テスト

この章では「開発を支える自動テスト」になるための、理論的な部分やアンチパターンなども説明されています。

その中でも私が特に心に残ったのは、「2-4-2 振る舞いをテストしていない」というアンチパターンの説明でした。

昨今、単体テストのプラクティスでも「内部の実装の詳細に依存するのではなく、機能の振る舞いをテストしよう」という考え方が以下のような書籍でも紹介されています。

https://book.mynavi.jp/ec/products/detail/id=134252

https://www.artofunittesting.com/

単体テストっぽく例を書くと以下のような形だと考えています。

// 機能の振る舞いをテストしている例
it("return true when prefix is AWS and serviceName is SecurityHub", () => {
    // 期待する振る舞いをテストしている
    // 「期待する振る舞い」が変更になったり、振る舞いを修正した時に正しく失敗してくれる
    expect(serviceName.isValid("AWS", "SecurityHub")).toBe(true)
})

// 内部の実装に依存している例
it("isValid", () => {
    const spy1 = jest.spyOn(serviceName, "isPrefixAws")
    const spy2 = jest.spyOn(serviceName, "ifPrefixAmazon")
    
    // 特定の名前の関数が呼ばれたという内部の実装の事情をチェックしている
    // 内部の関数名を変更するようなリファクタリングでもテストが失敗してしまう
    expect(spy1).toHaveBeenCalled()
    expect(spy2).toHaveBeenCalled()
})

これを例えばE2Eテストのテストコードに置き換えるとどうなるのか?

例えば「ボタンをクリック」という操作をコードとして記載する際に、「実装側の都合で消えうる属性」などを目印にボタンを見つけていると、特に振る舞いの変更をしていなくてもテストが頻繁に失敗してしまう可能性があります。

この書籍では後半の実践的なパートでも「どのように画面上の要素を見つけてアクションするか」という視点でもコメントを記載してくれているため、非常に参考になりました。

第4章 E2Eテストとは何か

この章ではE2Eテストの目的や責務、どのような性質を持っているものであるか?といったことを説明されています。

その中でも印象的だったのが「4-3-2 目的と制約を混同しない」の部分でに記載されている「E2Eテストでしかできないテストと、E2Eテストでやるべきテストは必ずしも一致しません」という部分です。

例えば私がSDETとして探索的テストをする際にも、実は以下のような保証的な内容も確認しています。

  • 画面に表示されるべきものが表示されているか?
    • 意図したラベルが意図した文字列で表示されているか?
    • 特定の条件のパラメーターを付与した時にページはどのように表示されるか
  • 画面の挙動が意図した通りに動作しているか?
    • ボタンを押した時にどんなふうに画面が変わるか?
    • ユーザーにどのようなフィードバックがされるか?

ですがこういった観点であれば、最近だとjsdomやStorybookなどのツールに機能面的なテストを寄せたり、より探索的かつ柔軟的な手法でQAエンジニアにはテストによりコストをかけてもらうということも可能だと思います。

むしろ「このような保証的な機能や、ユーザー基点の操作はコンポーネント側でもやろう」という認識合わせをしておくことで、開発のコンポーネント設計を見直すきっかけにもなるため、非常に重要な視点だと感じました。

第6章 最小限のテストをデプロイする

この章ではすでに第2部として既存のアプリケーションに対してE2Eテストを作成するハンズオン形式の部分になっています。

6-1-2 パイプラインから始める

この節で、まだテストコードもほとんどできていないような状態でも「開発サイクルにE2Eテストを組みこむ」という著者の考え方が書かれています。

この「たった1つのテストケースでいいからまずは自動化されている状態を作る」という考え方は、浅黄氏の以下の記事で発表されていたのを思い出しました。

私も同じような考え方を持っていたはずなのに、いつのまにか「今はタイミングが悪い」などの理由も込みでE2Eテストを後回しにしてしまっていることがあったことを反省しました。

確かに「全部のページでとりあえず正常に画面表示されている」「サインアップできた」「ログインしてダッシュボードが見えている」といった特定のプロセスのテストであっても、開発として安心感を得られていたなぁということを再認識しました。

今後は「開発を支え続ける自動テスト」の面でも力になれるように、この気持ちを忘れずに具体化して業務に活かしていきます。

6-4 テスト結果のレポートを出力する

テスト結果のレポートツールは、どうしても「あるとうれしい」程度のものとして扱われがちですが、筆者の経験上、ことE2Eテストにおいては「なくてはならない」ものです。これは、単体テストなどに比べて予期せぬ失敗が多く発生し、失敗の分析が頻繁に発生するためです。

私もE2Eテストのメンテをしている時に「え?何このエラー?どこで落ちてんの?」と言うことが多々ありました。

実際にOSSの Allure Report の例を交えてご説明いただいているのでシンプルに参考になりました。

https://allurereport.org/

7章 ビジネスプロセスをカバーするテストを作成する

この章では小さく作り始めた自動テストについて「代表的なビジネスプロセスをカバーする」形でテストを作っていきます。

個人的には「7-2 テストコードを置く場所を作る」では、E2Eテストシナリオを「ビジネスプロセスベースのもの」と「ユーザーストーリーベースのもの」を分けるためにディレクトリ構造を分けるという提案がありました。

確かに小さく自動テストを作り始める際には「特定のユーザーストーリー」に対してシナリオを作るよりも、「ここができなかったらやばい一連の操作」や「特に頻繁に使われる一連の操作」といったものから始めることが多いと思います。

また「この自動テストのシナリオのもと(テストベース)になったものは違うんだよ」と明確にすることで、テストコードの名前や構造化についても考えるきっかけになって非常にいいなと感じました。

9章 テストコードに意図を込める

この章では「小さく始めるために書き出したテストコード」をより改善していくためのヒントが散りばめられていました。

  • テストコードにコメントがたくさん書かれていて、それに頼り切っている
    • 例えばテストコードのタイトルや構造化を工夫して自己説明的なものにする
  • ユーザー目線のテストシナリオにする
    • 操作を羅列するのではなく意味のある単位で関数に切り出してあげる
    • ユーザーが操作をするにあたり例えばHTMLタグやCSSセレクターから要素を探しているのではなく、「ボタン」や「書かれている文字列」などで探す

などのようなポイントを具体的なコードとともに紹介してくれています。

個人的にはリファクタリングをするのが好きな性質なので、この章はとても面白かったです。

10章 トラブルシューティング

この章では例えば Flaky Test (失敗したり成功したりする)についての説明をしつつ、テスト結果の安定や決定性を高めるためのコードの書き方について述べられています。

個人的には「10-1-1 ソリューション:テストの独立性を高める」の部分が共感点が高かったです。

「テストの前提条件として特定の状態をDB上に用意する場合、既存データを使うのか、テストデータを都度作るのか、作るならどうやって作るのか」といった部分は最初に考えることが多いので、意見を明示されているのがとても素晴らしいと思いました。

なお、この点について以前 JaSST nano というイベントにおいてSmartHRのtanoさんという方が発表をされていました。

こちらも合わせて見ていただけると、より解像度が上がるかと思いました。

https://tech.smarthr.jp/entry/2024/04/16/210527

まとめ

今回書ききれないくらい「なるほどぉ〜」「わかるわぁ〜」と思った箇所があったのですが、全部を細かく書くとネタバレになるので避けました。

この書籍は特にフロントエンドエンジニアでE2EテストとUIテストについて考えている方であったり、テスト自動化を推進するけどあまりコードを書いたことがないと言う方にとっても非常に参考になると感じました。

全体として「目的」や「なぜか」ということを抑えた上で実践パートに入りつつ、概念的な話に終始せずに具体的なコードを交えているのがとても素晴らしかったです。

開発としてもQAエンジニアとしてもご活躍されている筆者の経験が詰まった良書だと思います。

もしご興味がある方がいらっしゃいましたら、ぜひ手に取ってみてください。

以上、乱文失礼しました。最後までお読みいただきありがとうございました。

GitHubで編集を提案
Money Forward Developers

Discussion