2017-11-07

初めての自動テスト ―Webシステムのための自動テスト基礎の要点をまとめました

オライリー社から出ている、「初めての自動テスト ―Webシステムのための自動テスト基礎」という書籍を購入したので、まとめます。


初めての自動テスト ―Webシステムのための自動テスト基礎
Jonathan Rasmusson
オライリージャパン
売り上げランキング: 7,685


そもそも買った動機とか、知りたかったこと


  • そもそもデータサイエンス領域でSelenium芸を使っていたが、本来テストで使うらしいので興味を持った
  • テスト初心者なのでどんなことをやっているのか知りたかった
  • 自動テストと人がやるべきテストの切り分けを知りたかった
  • テストの種類を知りたかった
  • 品質保証が受け持つ範囲と、その他の受け持つテストの範囲を知りたかった


一応すべてに答えてくれたので良かったと思います。(ただし紹介されるコードはRuby on Railsなので、書いたことない人にとっては厳しいかもです汗)





自動テストでやりがちなアンチパターン


テストにはUIテスト・統合テスト・結合テストがあります(後述)
その中で、UIの部分に関するテストにこだわりすぎると、泥沼にはまるそうです。


UIテストとは、実際にWebブラウザ上で人が操作しているかのように行う自動テストです。例えば、フォームに名前を入れたり、送信ボタンをクリックしたりとう、人間のテスターがやる領域ですね。


で、アンチパターンとして、ひたすらUIテストだけ作り続けるというものがありますが、UIテストには以下の欠点があり

(1)UIテストを増やしすぎて、ビルドに時間がかかる→テストをしなくなる
(2)UIテストは壊れやすく、また壊れたテストの修正に多大な時間をかける


こういう脆いテストの上に、新規に開発してソースコードを加えていくと、最後にドカーンと壊れてしまうことが多いそうです。



自動テストの3つの教訓


先ほど紹介したアンチパターンは著者の苦い経験らしいので、UIテストにこだわらず、


  • それぞれのテストには得意不得意があること
  • それぞれのテストの「書くべき理由」を見出す(書きやすいからと言って書かない)
  • スピードとフィードバックが大事なので、テストケースを短くし、反復回数を上げること


が必要らしいです。


テストのピラミッド


テストの種類と特徴について。UIテストと統合テストとユニットテストがあるそうです。


  • UIテスト
    • Webブラウザ上で実際に人が操作しているようなテスト。 ユーザーと同じ対象を見れるUI側のテスト。全ての層がつながっているかをテストし、システムの最終的な品質を検証するために使われる。欠点として、ビルドが遅く、またフィードバックも不明確。最終的な品質保証を行うためのテスト。
  • 統合テスト
    • 複数層がつながっているかみれ、内部の複数のロジックをまとめて検証するテスト。サービス層ロジック層を担当。UIの壊れやすさに影響を受けない。また、インターフェイスを持たないAPIのテストができる。実行もUIテストよりも早く、またレスポンスも正確。品質保証を行うためのテスト。詳細さに欠ける
  • ユニットテスト
    • 内部のビジネスロジックを検証するコード。ロジック層を担当。実行もフィードバックの正確さも一番早い。超高速。多目的に利用できる。どの部分がうまくいかなかったのかがすぐわかるので、開発サイクルを早め、改善を行いやすくできるため、製品開発側のプログラマーが作ることが多い。欠点として、ロジック間のつながりを検証することができない



親指の法則

できるのであれば、どんどん下位のテストで検証すべきとのこと。


  • UIよりもユニットテストを優先すること
  • ユニットテストで埋められない部分を結合テストでカバーすること
  • UIテストは限定的に使うこと
  • 新しいテストを追加するときは、常に「ユニットテストでカバーできないか」を最初に確認しよう
  • 常にテストをできる限りピラミッドの下の層に入れること
  • 全てを自動化しようとしないこと。代わりに過不足なく自動化しよう


ユニットテスト VS UIテスト



  • 目的
    • ユニット:開発のためのもの
    • UI:検証のためのもの
  • フィードバック
    • ユニット:フィードバックが早い
    • UI:遅い
  • レベル
    • ユニット:下位レベル
    • UI:上位レベル
  • コスト
    • ユニット:低コスト
    • UI:高コスト
  • 実行速度
    • ユニット:早い
    • UI:遅い
  • 頑丈さ
    • ユニット:固い
    • UI:もろい
  • 結果
    • ユニット:信頼できる・結果が一意に決まる
    • UI:信頼できない・結果が一意に決まらない
  • 何のために使う
    • ユニット:開発サイクルの向上
    • UI:品質保証
  • 視点
    • ユニット:開発のため
    • UI:顧客のため


開発者 VS テスター



  • 開発者:素早いフィードバックと正確さが欲しい。ユニットテストをメインに
  • テスター:品質保証。統合テストとUIテストがメイン


UIテストに触れる



  • UIテスト = 「接続性」のテスト
  • 高レベルなスモークテストとして利用される
  • スモークテスト:
    • アプリケーションが適切にディプロイされている
    • 環境が適切に設定されている
    • アーキテクチャのすべてのパーツが正しく接続されている
    • システムが常に稼働していること、最低限のレベルで保証してくれること
  • キャプチャーリプレイを避ける
  • UIテストは緩く保つ。詳細なUIと結びつけてはいけない。


統合テストを学ぶ



  • 見落としていたバグを見つけられる
  • 十分な堅牢性と十分な機動性(スピードとフィードバック)を兼ね合わせている


Webの仕組み


  • UIがない場合のテストは、RESTな通信で対応する
    • URL
    • DNSルックアップ
    • IPアドレス
    • プロトコル(http)
    • ポート
    • リソース
  • 全てのサービスがUIを持っているとは限らない(API)ので、バックエンドロジックでテストできる必要がある
  • 動作が重いUIテストを代替する方法として、統合テストが使われているパターンもある


REST(Representational State Transfer)



  • HTTP GET (取得)
  • HTTP POST (送信)
  • HTTP PUT (更新)
  • HTTP DELETE (消去)


テストのコツ



  • 正しく動くことを保証する
  • 壊れる可能性のある個所はすべてテストする
    • エッジケース
    • 特殊条件
  • テストファースト
    • 必要なものだけを実装できる
    • テストしやすく部品課された状態でシステムを設計、実装できる
    • 実装が完了するとその動作を保証するユニットテストもできあがっている

モックテスト





クライアントサイドとサーバーサイドの言語



  • JavaScript
    • クライアントサイド(Web ブラウザ)のスクリプト言語
    • UIテストも局的に行うので、UIのユニットテストも存在する
    • テストフレームワーク:Jasmin https://qiita.com/opengl-8080/items/cf3acafda9756f4b04c9
  • Ruby
    • サーバーサイドのスクリプト言語
    • RSpec


静的型付けと動的型付け



  • 静的型付け
    • コンパイル時に型検査を行ってくれる言語
    • JavaとかCとか
  • 動的型付け
    • コンパイルしないので型検査を行ってくれない言語
    • Javascriptなどの言語は、型検査がないので、ユニットテストによる検査が大事になってくる

ピラミッドの型を上る



  • ユニットテストから始める
  • eXtream Programming:「 妥当と思える範囲はできるだけテストするが、本当にすべてのテストはできないことを意識しておく」
  • できるだけたくさんのテストをピラミッドの下の層、つまり高速で信頼性が高く、より安定したテストが実行できる層へ押し込めるべき


テスト初心者のアンチパターン



  • 逆ピラミッド
    • 特徴
      • 多くのUIテスト
      • ほんのわずかなユニットテスト
    • なぜ起こるか
      • 少ない労力で、包括的にテストを行いたい→UIテストへ
    • 何が起こるか
      • 脆弱なコードですぐに壊れ
    • 例外
      • レガシーなシステムで、ユニットテスト、統合テストが存在しない場合はUIテストから入ってもよい
  • 不安定なテスト:信頼性をもって実行できないテストのこと(一回でも失敗する)
    • 対応策
      • テストを書き直す
      • テストをピラミッドの下の層へ移動させる
      • 価値のないテストとみなしテストを止める


テストを整理する



  • テストを分離する
  • コンテキストを明確にする
    • UIテスト → 画面ごとに分ける
    • 統合テスト → サービス・エンドポイント
    • ユニットテスト → クラス・インターフェイス
  • 似ているものをまとめる


効果的なモックの活用



  • 依存性の代入
  • 結合による束縛
  • モックを使いすぎて泥沼にはまらない


テストファースト



  • テスト稼働開発(TDD)
    • ステップ1 失敗するテストを書く
    • ステップ2 テストを成功させる
    • ステップ3 リファクタリングする


感想


テストの種類とか、実際のサンプルコードが豊富で理解しやすかったです。

初めての自動テスト ―Webシステムのための自動テスト基礎
Jonathan Rasmusson
オライリージャパン
売り上げランキング: 7,685

注目の投稿

 PythonのTweepyを利用して、Twitter APIを利用している。 その中で、ハマったポイントをメモしておく。 まず、Searchに関して。 Twitter検索は、クライアントアプリ側では、全期間の検索が可能になっている。 一方で、APIを利用する際は、過去1週間しか...