今回は、自分の仕事の実体験を含めて、自動テストの全体像がわかるようにまとめてみたいと思います(新卒の知識なのでそこまであてにしないでください。)
翔泳社 (2014-12-17)
売り上げランキング: 17,628
売り上げランキング: 17,628
自動テストを導入するとどんないいことがあるのでしょうか、また、どんな問題があるのでしょう。今回は、システムテスト自動化標準ガイドという本を参考に、まとめてみたいと思います。
1. 自動テストとは何じゃらほい
自動テストには、様々な種類があります。それは以前に紹介した、初めての自動テストにもある通り、大きく分けて以下の3種類があります。
- 単体テスト:プログラマーのデバック向けのテスト
- 統合テスト:単体テストで通ったモジュール(部品)を組み合わせて行うテスト
- UIテスト:実際に利用するシステムのユーザーフローに沿ったテスト
2. 開発者向けのテストと、品質保証向けのテスト
開発者の中でよく行われるのは、単体テストと統合テストですね。こちらは、プログラム自体のテストになり、その入力と出力の処理結果が可視化されるので、ホワイトボックステストと呼ばれています。実際にユーザーが触れるUIではなく、システムの中身だけでテストを行います。
これらのテストは、コードの修正時に不具合を発見し、より早く開発を進めるために書くことが多く、自動化されやすいです。rubyでいうRSpecのソースコードを読んてみると、なんとなくどんなことをしているのかイメージがつくと思います。RSpec テストコード書き方 サンプル _φ(・・*)
require 'rails_helper' RSpec.describe Admins::TasksController, :type => :controller do describe "GET #index" do login_admin before(:each){ create_list(:task, 3)} context "デフォルト(条件指定のパラメータがない場合)" do before(:each){ get :index } it "解決済み(done: true)は返さない" do create(:task, done: true) expect(assigns(:admins_tasks).pluck(:done)) .to_not match_array([true]) end it "返される数は、20件以下のlimitがかかっていること" do create_list(:task, 21) expect(assigns(:admins_tasks).count(true) <= 20).to eq true end end it "params[:note_id]で指定があれば、それを返すこと" do note = create(:note) task = create(:task, note_id: note.id) get :index, note_id: note.seq expect(assigns(:admins_tasks).count).to eq 1 end describe "params[:search]で検索条件があれば、それを返すこと" do it "コメント検索" do comment = "コメント" task = create(:task, comment: comment) get :index, search: {comment: comment} expect(assigns(:admins_tasks).last.comment).to eq comment end it "メモ検索" do memo = "メモ" task = create(:task, memo: memo) get :index, search: {memo: memo} expect(assigns(:admins_tasks).last.memo).to include memo end end it "renders ther :index template" do get :index expect(response).to render_template :index end end describe "POST #create" do context "with valid attributes" do it "saves the new record in the DB" do expect{ xhr :post, :create, task: attributes_for(:task, note_id: note.id) }.to change(Task, :count).by(1) end it '@task_note_seq be valid' do xhr :post, :create, task: attributes_for(:task, note_id: note.id) expect(assigns(:task_note_seq)).to eq note.seq end end context "with invalid attributes" do it "does not save the new record in the DB" do expect{ xhr :post, :create, task: attributes_for(:invalid_task, note_id: note.id) }.not_to change(Task, :count) end end end describe "PATCH #update" do login_admin let(:task) { create(:task) } context "valid attributes" do it "locates the requested" do xhr :patch, :update, id: task, task: attributes_for(:task) expect(assigns(:task)).to eq(task) end it "changes attributes :done" do xhr :patch, :update, id: task, task: attributes_for(:task, done: true) task.reload expect(task.done).to eq true end it "changes attributes :memo" do memo = "メモ" xhr :patch, :update, id: task, task: attributes_for(:task, memo: memo) task.reload expect(task.memo).to include memo end end context "with invalid attributes" do it "does not change" do xhr :patch, :update, id: task, task: attributes_for(:task, done: "test") task.reload expect(task.done).not_to eq "test" end end end end
このテストは、実際にブラウザを操作せず、内部にユーザーのデータを作成し、DBにいれて・・・という操作を、UIを経由せずにプログラム上で実行し、それが正しい結果を取得できているか調査しています。UIとは完全に分離したテストなわけですね。
逆に、今回の本で説明されているのは、3のUIテスト(総合テスト・機能テスト)は、中のプログラムを直接見るわけではないので、ブラックボックステストと呼ばれています。
この本で扱っているのは、どちらかというとUIテスト・ブラックボックステストの自動化の部分になります。
2. UIのテストってどんなことするん?
このUIテストは、例えばECサイトで「買い物を行う」というユーザーの欲求をもとに説明すると、例えば以下のような行動を実際に品質保証チームがブラウザで操作し、要求を満たせているか確認するわけですね。
- ブラウザを起動する
- ログインする
- 買い物一覧を検索する
- 買い物一覧画面に飛ぶ
- 詳細ページに飛ぶ
- 購入ボタンを押す
- 確認画面に飛ぶ
- 決定を押す
- 購入完了ページに移る
「え?そんなことしなくても、単体テストと結合テストやれば済むじゃん」と思われるかもしれませんが、例えば単体テストで商品の閲覧から購入までのテストが通っていたとしても、UIの部分のソースコードが間違っていたら、要求は満たせません(購入ボタンのリンク切れが起こっている可能性もありますし、javascriptが動作していないかもしれません)また、仮にテストが通ったとしても、ユーザーにとっては不便かもしれません(確認画面を押すのに、10秒待たないといけない設定になっていたら、それは品質保証が指摘すべきです)
3. 自動テストで自動化するのは、UIテストの中でどのようなテストか
このUIテストには、段階・目的によっていろいろなテストがあります。JSTQBによると以下のようなテストがあります。
- 機能テスト(functional testing): コンポーネントやシステムの機能仕様の分析に基づいて実施するテスト。black box testing も参照のこと(JSTQB 用語集から)
- 確認テスト(confirmation testing): 修正が成功したかを検証するために、前回不合格に終わったテストケースを再実行するテスト。(JSTQB 用語集から)
- 回帰テスト(regression testing): 変更により、ソフトウェアの未変更部分に欠陥が新たに入り込ん だり、発現したりしないことを確認するため、変更実施後、すでにテスト済みのプログラムに対して実行するテスト。ソフトウェアや、実行環境が変わる度に実施する。(JSTQB 用語集から)
普段仕事でテストしている感じだと、新規機能が開発されて、機能テストを最初に行い、その後バグを見つけて報告、その報告に基づいて機能が修正され、確認テストを行い、最終的には回帰テストを行うといった流れですね。
この最後の、回帰テストを自動化することが、品質保証でいう、いわゆる自動テストです。
4. 回帰テストを自動化するとどんないいことがあるのか
用は、まったくおんなじテストを何度も繰り返すのは、機械で自動化できるからです。そして、回帰テストを自動化するメリットはたくさんあります。
テストをもっと頻繁にたくさん行えるようになる
回帰テストを自動化すると、より早く、いつでもテストすることができるようになるので、ソフトウェアの未変更部分に欠陥が新たに入り込ん だり、発現したりしないことを確認する回数が増えます。そうすると、バグの検出がより早く行えるようになり、開発者へのフィードバックが早くなったり、品質の欠陥をより早く修正することができるようになります。
手動テスティングすべきテストに人を回せる
バグの検出率が一番高いのは、手動テスティングです。実際、一度行われたテストから、エラーが多く検出されることはありません(なぜならテストを最初に実行したときに一番エラーを検出することができ、あとはディグレを検出することしかできないからです)
回帰テストは、多くの時間を取られる割にはバグを見つけられることは少ないので、本来であれば手動テストでより多くのバグを検出する時間に、回帰テストで自動化した時間を充てることができるようになります。
また、同じテスト入力を繰り返し入れ続けるような、単調で退屈な仕事を自動化すると、はるかに正確になるだけでなく、作業者の士気も高まります。また、優れたテスト担当者を解放し、よりよいテストケースの設計に注力させられることができるようになります。
市場に早く提供できる
いったんテストが自動化されると、手動よりもはるかに速く繰り返され、結果的にテスティングに必要な時間は短くなります。
より早く正確にテストできる
人間だと、単調でつまらない回帰テストを行っていると、集中力がなくなり、テストを間違えたり、やり直したりする中でかなり時間がかかってしまいます。一方自動化すると、人間の100倍以上の速さでテストを行ってくれ、かつ正確に実行するので、より早く正確にテストをすることができます。
— Dai Kawai@RubyPython (@never_be_a_pm) January 31, 2018
#QA #read— Dai Kawai@RubyPython (@never_be_a_pm) February 3, 2018
テスト入力と出力が明確なテストは再現性が高く、最も自動化しやすいテストだが、同時に最もクリエイティビティを求められないテスティングとなる。クリエイティビティと再現性はトレードオフ?
5. 回帰テストを自動化するときの問題点
で、ここからが本題。自動テストを作るときに注意したい点です。
過度な期待:全ては解決できない
ぶっちゃけた話、すべてを自動テスト化するのは誤りです。自動テストは、すでにテストした内容を自動化するだけなので、プログラムに機能を追加したり変更を加えたことによって、今まで普通に動いていた部分が動かなくなっていないかを確認することしかできません。
#read— Dai Kawai@RubyPython (@never_be_a_pm) January 31, 2018
テスト自動化の問題点
1. 過度な期待:全ては解決できない
2. 不正確なテスティング:テスティングの効率より、先に効果を上げて自動テストを書く
3. 自動テストは新しいバグを見つけてくれるという期待:バグはテスト新規作成時に生まれる。自動テストはリプレイツール
自動化すべき回帰テスト・すべきではない回帰テストとは
自動化すべき回帰テスト:修正が少ない部分のコンポーネントである
せっかく回帰テストを書いても、機能の修正が大幅で、自動テストコード自体が意味なくなってしまうことも多々あります。自動テストを行う機能が、今後修正が少ない部分であれば、なんどでも使えるので、自動化することを検討するとよいでしょう。逆に、すぐ修正が加わる部分は、自動テストには向いていません。
これは個人的にスクレイピングツールを作成しているときでも感じるのですが、少しHTMLのClassやIDが変わるだけで、自動化スクリプトは全滅します。
また、そういうテストを自動化してしまうと、後で自動テストをメンテナンスするコストが高まり、本来かけるべき新しいバグ検出ができなくなってしまいます。
#QA— Dai Kawai@RubyPython (@never_be_a_pm) February 2, 2018
自動テストがバグってたりすると、ほんとうは本質的なエラーを探す探索テストにかけられる時間が、メンテの方に持ってかれてしまう。自動テストでエラーが起こると、調査、修正コストがかかるし、それが頻繁だとリグレッションテストすらできなくなるなぁ。
翔泳社 (2014-12-17)
売り上げランキング: 17,628
売り上げランキング: 17,628
就活に関するおすすめ記事
就活中には、なるべく採用担当以外のリアルの経験を聞くべき5つの理由
【今だったら絶対にやってた】就活弱者の僕が今になって思う、大学2-3年生の時にやっておくべき3つのこと
メガベンチャーへの就職をしてみたいなら、OBOGに聞いてみよう
エンジニア就職に関するおすすめ記事
新卒未経験でエンジニアになるには?大学生でエンジニア就職している人に知っておいてほしいことフリーランス・エンジニアとして独立するときによさそうなミッドワークス(Mid Works)についてまとめてみた