nobu blog

プログラミングやゲームの話など。

*



【オライリー本感想】Seleniumデザインパターン&ベストプラクティス はUIの自動テストのガイドとして良くまとまっている良書

   

概要

今回はオライリー本の、「Seleniumデザインパターン & ベストプラクティス」に関しての感想を書きます。

本書はSelenium WebDriverを使ったテストの構築方法やデザインパターン、メンテナンス性に焦点を当てた書籍です。
Webシステムの自動テストを始めたい方を対象に、自動テストの考え方やフレームワークを解説する書籍です。

スポンサーリンク

書籍概要

どんな本?

本書はSelenium WebDriverを使ったテストの構築方法やデザインパターン、メンテナンス性に焦点を当てた書籍です。
Seleniumを使った人ならわかるテスト時の取り入れるべき事柄や避けるべき事柄をパターン化してわかりやすく解説しています。
テストをリファクタリングする方法、自動テストプロジェクトにおけるSpaghettiパターン、テストデータについて、テストを安定させるコツ、さらにテストスイートを成長させるヒントなど、テスト自動化設計におけるポイントを幅広く紹介します。
ベストプラクティスだけでなく、アンチパターンも紹介しているため、失敗の原因を知り、適切な設計パターンを適用することができるようになります。

  • Dima Kovalenko 著、玉川 紘子、太田 健一郎 監訳、笹井 崇司 訳
  • 2015年09月 発行
  • 256ページ
  • 定価3,300円(税込)

スポンサーリンク

内容のまとめと感想

Webアプリケーションのための自動テストツールである、Seleniumに関して各種デザインパターンやノウハウをまとめた書籍になっています。

ボリュームも程よく、翻訳もわかりやすくてかなり読みやすいのも良い点です。

言語としてはRubyを用いていますが、APIとしては各言語とも大きい違いは無いので、Rubyを知らなくても読む上でそこまで障害にはならないと思います。

テストコードのデザインパターンの説明とメリット、デメリットを説明し、実際のコード例を使って説明するという流れで進むので理解がしやすくまとまっています。
デザインパターンと紹介されていますが、機能の実装におけるデザインパターンのような複雑なクラス構造などを意識したものではなく、単純な実装方法のノウハウ的な側面が強いので肩を張れずに読めます。

Seleniumをベースにした実装の説明になっていますが、考え方やデザインパターンなどはその他のUIの自動テストにも適応できる汎用的なノウハウが多いので、Selenium以外でもUIの自動化を行うエンジニアなどが読むと参考になると思います。

BDD(振る舞い駆動)に関しても説明があり、定番のCucumberの説明もあります。
なんとなくは知っていたのが実際にコードなどの説明もあり、参考になりました。
ただし、Cucumber自体を使いこなしたいならば、もう少し別の教材や自学が必要だと思います。

全体としてあくまでインテグレーションテストや、E2Eテストを主眼に置いた話やノウハウになるので、単体テストやシステムテストなども含めた総合的なテスト戦略を学ぶのには、同じくオライリーから発売されている、「初めての自動テスト」が役立つと思います。
(私も久しぶりに読みたくなりました。)

Webシステムの自動テストを始めたい方を対象に、自動テストの考え方やフレームワークを解説する書籍です。

読みやすくサラッと読めるので、UIの自動テストを行なっている/興味があるエンジニアは一度、目を通して見ることをおすすめします。

スポンサーリンク

読書ノート(個人的なまとめ)

第1章 最初のテストを書く

まずは、導入としてSeleniumの特徴と、ノーコードでテストが生成できるSelenium IDEを使用したテストの実施方法を説明しています。

操作記録系のテストって確かにコードが書けない非エンジニアでも作れてしまうので、敷居は非常に低いのですが、テストコードのメンテナンスが大変だったりで、現実的にはあまり使用はされていないのではないかと思っています。
結局本書でも導入として最初にちらっと紹介するにとどまっているので、あくまで最初の第一歩や元となるテストコードを生成したい時などには有効なツールとして認識しておいた方が良いかなと思いました。

  • Seleniumを選ぶ理由
    • 適材適所:Webアプリケーションの操作テストに最適
    • 価格:無料
    • OSS:多くのナレッジやコミュティがある
    • 柔軟性:大抵のブラウザで動く。モバイルでも。ヘッドレスモードでも動く。
  • Record and Playbacパターン
    • ユーザの操作を記録して、再生可能にする方法
    • ブラウザのプラグインとしてSelenium IDEがあり、それで簡単に記録やコード生成できる(様々な言語に出力可能。Java,C#,Ruby,Python etc)
      • ●メリット
      • 短時間でどんどんテストケースが作れる
      • 非プログラマーでもテストケースが作成可能
      • ●デメリット
      • 生成されるコードが汚い(絶対パスのロケーターや冗長なコード)
      • テストデータの柔軟性がない(記録したテストパターンのみ)
      • テストのメンテナンスコストが高い
  • UnitTestツールとの統合
    • Selenium自体にはテストとしてのアサーション機能は無い
    • 利用する言語に合わせたUnitTestフレームワークと統合して使用する
    • 本書ではRubyでの説明のため、Test::Unitと統合している

第2章 Spaghettiパターン

実際に題材となるWebサイトのテストコードを書きながら、アンチパターンであるSpaghettiパターンに関してや、要素の指定方法(ろケータ)に関して学んでいきます。

  • Spaghettiパターンとは
    • アンチパターン。様々なテストが依存や統合してからまっている状態。
    • ●メリット
    • お手軽で、コードベースが少ない。スモークテストに適している
    • ●デメリット
    • 保守性は最悪
    • 密結合しているので、再利用は難しい
    • 並列実行やランダム実行などの柔軟性がない
  • ロケータ
    • 特定の要素を抜き出すための方法。
    • IDやクラス名、リンクテキストやタグ名、セレクタなど指定方法は様々
    • IDが一番高速で確実。
    • 使えない場合には、パス指定。ただし絶対パスはもろいので厳禁。相対パスとする。
    • 密結合しているので、再利用は難しい
    • 並列実行やランダム実行などの柔軟性がない

第3章 テストをリファクタリングする

2章で作成したアンチパターンのテストコードの実装をリファクタリングしながら、テストコードのプラクティスを学んでいく章です。

  • DRYテストパターン
    • コード実装で有名なDRYの原則をテストコードに適応させたもの
    • 重複したテストコード、テスト項目を取り除く
    • お手軽で、コードベースが少ない。スモークテストに適している
    • ●メリット
    • テストのモジュール化によるコードの共通化
    • テストの更新しやすさ
    • ●デメリット
    • 構造が複雑化
    • 常に管理が必要
  • DRYの実装例
    • setupとteardown(準備と後始末)の機能による処理の分離
    • 重複した処理があれば共通のメソッドを作る
    • 本来のテスト目標と関係ないアサーションは除外する
    • Hermeticテストパターン
      • Spaghettiパターンの対極。全てのテストは独立して影響を受けないようにする。
      • ●メリット
      • 前後のテストの操作やデータに影響を受けない
      • 他のテストが失敗しても影響を受けにくい
      • モジュール化されて、テストの組み替えやスモークテストに組み込んだりする柔軟性がある
      • テストの並列実行が可能(実行時間減少)
      • ●デメリット
      • 設計が必要
      • 1個のテスト時間は長くなる(個々のケースが準備や後始末を持つ)
    • ランダム実行順序
      • DRYな構造にする事で毎回ランダムなテスト順序で実行が可能になる
      • 隠れたテスト依存関係を見つけるのに役立つ(あると失敗する)

      第4章 データ駆動テスト

      ハードコードされたテストデータを外部の設定に依存する形に変更する方法を説明する章です。

      • テストデータをテストから隠蔽する
        • ハードコードされた入力デーやURL等のデータを外部から読み込む形に修正する
        • テスト環境(ローカル、ステージング、本番等)は環境変数から読み込む
        • テストフィクスチャ(YAMLなどの外部ファイル)に各種テストの説明や入力値を記載する
      • 複数テストモデルと単一テストモデル
        • 複数テストモデル:個々のパラメータ毎(例:商品データ)にテストケースを書く
          • メリット:テストが明確になり、失敗時もわかりやすい。並列実行も可能
          • デメリット;冗長で重複したテストケースができる
        • 単一テストモデル:1つのテストケースで複数のテストデータを処理する(ループで複数商品をチェックする)
          • メリット:コード重複が少ない。複数テストケースより総実行時間は高速。
          • デメリット;失敗原因がわかりにくくなる。1テストの実行時間が長くなる
          • 失敗時の原因をしっかりとわかるような注意を払って実装することでデメリットは軽減可能。
      • データスタブ
        • 外部APIなどの依存サービスは本当にアクセスせずに極力スタブ化する。(例:JSONファイルを用意してその値を返すようにする)
      • Default Valuesパターン
        • 対象のテストケースで重要でないデータは、デフォルト値を決めてそれを利用する。(例:ログイン機能のテスト以外のテストケースでは、ログイン情報は統一する。)
        • ただし、データが均一になってしまう問題があるがfakerのようなライブラリで回避可能
        • faker
          • rubyのgem(ライブラリ)
          • 氏名やメールアドレス、タイムスタンプなど毎回データをランダムでもっともらしい値を生成してくれる。

      第5章 テストを安定させる

      テストの安定実行に関する考えやノウハウを説明した章です。
      テストが安定的に実行されて、無視されないような環境や考えが醸造される事が大切ということを述べています。

      • 安定を保つ文化カルチャを築く
        • すばやく実行して、すばやく失敗させる
          • 目標:テスト全体は10分以下で終わるように。(平行実行)
          • テストが失敗したら即座に開発者にメールを送信
          • とにかく開発者を待たせない
        • できる限り頻繁に実行する
          • ビルドチェーンの最後で実行するのはアンチパターン(そもそもUIの自動テストは時間がかかるし、その前のタスクで失敗する可能性がある)
          • 待ってる間にコミットが何個も実行されてる可能性もある
        • クリーンで一異性のある環境を保つ
          • 本番環境と極力同じテスト環境を用意する(Chiefなどの環境の構成管理ツールを使用する)
          • テストケース事に環境をリセットできるようにする(DBのリロードなど)
        • 間違ったコード変更を捨てる
          • テストにPASSしないコードはmasterにコミットを許さないようにする(構成管理ツールの機能を使用する)
        • 安定したテストスイートを維持する
          • Ajaxや実行時間が遅くなるような要因を見つけ、早く取り除く
      • 安定性を向上させるためのパターン
        • Action Wrapperパターン
          • クリック、入力、Ajax、アニメーション処理などのアクションを1つの場所に集める
          • 見つけやすく、変更しやすくDRYなコードになる。エラーの原因特定やトレースもしやすくなる。
        • Black Hole Proxyパターン
          • 外部サービスの接続部分はテストを不安定にする要因 → スタブ的にリクエストを受け取り外部へのアクセスをブロックする。
          • 不安定な外部システムから独立され、安定性が向上する。
          • レイアウトが崩れたり(例:SNSのボタンなど)、外部との接続テストが壊れないように注意が必要
          • Seleniumの機能でHTTPプロキシの機能があるのでそちらを利用する。 (外部へアクセスするURLをローカルにフォワードできる。)

      第6章 ふるまいをテストする

      ふるまい駆動開発(BDD)に関する説明している章です。
      具体的にどういったものなのかを説明し、CucumberといったBDDによる記述やテストを可能とするツールを紹介しています。

      • 振る舞い駆動開発(BDD)
        • 最初から最後までアプリがどのように振る舞うべきかを第一に考える
        • BDDのフレームワークを使用して実装する
        • メリット:テストの理解度が高まる。(コードの記述内容によって混乱しなくなる)
        • デメリット:標準を定めて用語の統一が必要。最初の学習コストが高い。
      • BDDの実装方法
        • Dan Northによる記述方法
          • Given,When,Thenという形式でテストの方法を記載。下記の機能を使用して、振る舞いを定義する。
          • Feature:機能全体の概要を記載する(例:ユーザーはカートに商品を追加できる)
          • Scenario:テストデータのパターンを記載する(例:匿名ユーザはカートに商品を追加できる、ログインユーザは・・・)
          • Given:テストの出発点、前提条件(例:匿名ユーザは商品ページを開く)
          • When:特定のアクションを実行するための条件を記載(例:アイテムをカートに追加した時)
          • Thenと:アプリの採取状態を定義。アサーションとして使われる
      • Cucumber
        • BDDの振る舞いを定義してテストとして実行可能にするツール
        • Featureといったファイルに、上記Given,When,Thenを定義して書く。

      第7章 Page Objectパターン

      前章でも説明されたBDDを使用したテストの実装方法の1つとして、Page Objectパターンを紹介しています。
      ページの操作を隠蔽して、外から見た操作に置き換える方法で、テストコードの可読性向上にもつながりそうです。

      • Page Objectパターンとは?
        • ページの操作をオブジェクトとして隠蔽する。
        • テストは直接ページとやりとりせずに、このオブジェクトを介して操作する。(XXXの商品を探すといったメソッドを呼び出す。)
        • メリット:操作が理解しやすくなる。BDDと同じくふるまいによるテストになる。モジュール化される。
        • デメリット:複雑さの増加。

      第8章 テストスイートを成長させる

      テストスイートをどのように実装して、成長させていくかの戦略に関してまとめている章です。
      やみくもなテストスイートの作成ではなく、何に優先度を置くべきか書かれていて参考になりました。
      特に最初から作るのではなく、後からこういったスイートを追加することになったプロジェクトにおいては参考になるではないかと思います。

      また、後半はテストスイートのCIへの統合方法が書かれています。
      この辺りはCD/CIやってれば知っている内容が多いので流し読みでも良いかも。

      • テストの戦略
        • 資源は有限。テストスイートの成長戦略が必要になる。(何を優先して作るか?)
      • スモークテストスイート
        • デプロイ後に本番環境が動くかどうかの素早いチェックが目的(あまりテストしすぎない)
        • 重要なページが500エラーとならないかのチェック
        • DBと接続のエラー、JSのエラーが出てないかチェック
        • 重要なページが500エラーとならないかのチェック
        • DBを戻すのが難しいなら読み込みだめのテストでも良い
      • マネーパステスト
        • アプリケーションの主要機能(お金を生み出す機能)のチェックが目的
        • スモークと違ってDBへの書き込みも含めてチェック
      • 新機能戦略
        • リグレッションよりも、新規開発した機能のテストを一緒に追加する
        • 必須の機能でなければやらなくても良い。それならば重要な既存機能のリグレッション用テストを作る。
      • バグ駆動戦略
        • バグ修正時に一緒にテストケースを追加する
        • これが積み重なるとセーフティネットになる
      • 99%カバレッジスイート
        • 新機能と既存機能の99%カバーするような事は非現実的
        • バグ駆動戦略などで徐々に積み上げていく事が大事
        • 有用性の不明な大きいテストスイートより、小さくて頻繁に実行できるスイートの方が優れている

       - 技術書, 読書感想