フリーキーズ | 独学プログラミング

【初級エンジニア向け】テストって何?から一歩先へいくテスト習慣付けのススメ

最終更新日
【画像】【初級エンジニア向け】テストって何?から一歩先へいくテスト習慣付けのススメ

「テスト」という言葉を聞いて、なんとなく気後れしてしまうことはないでしょうか。
もしあるとしたら、ぜひこのコンテンツをご覧ください。

運営者である田邉はエンジニアを長らくしている中で、きちんとすべてのコードにテストが施されている案件は1つもありませんでした。開発チームによって、テストが90%以上書かれていることもあれば、全体の10%にも満たないテストコードのプロジェクトもあります。
もし所属している開発チームがテストに消極的であれば、ぜひあなたがテスト徹底のリーダーとなり、コードの品質向上を牽引していきましょう。

テストを書いた現場、書かなかった現場

まずは実際の体験談を紹介します。
様々な開発チームにジョインしてきましたが、その中でもテストを書く・書かないはチームによって大きく異なっていました。

結論から言えば『容赦なくテストのないコードを却下(GithubでいうApproveされない)されるほうが品質は高いサービスを提供している』です。当たり前のことではありますが、経験しないとこの感覚は理解しづらかったりします。

Approveされない現場

数年前の現場の話です。
コードを仕上げ、GithubでPull requestを送り、コードレビューを受けた際に、最初に「テストを書いてください」とコメントされる現場がありました。急ぎの修正(hotfix)でもなく、ジョインしたばかりで緊急度の高い機能を作っていたわけでもなかったので、そのままテストコードを追加して再度レビュー依頼を投げApproveされました。

このときすでにエンジニア歴数年でしたが、それまで最初のコードレビューでテストを求められたことはありませんでした。それまでの現場が緩かったかと言われればそんなことはなく、ただテストを書くことの優先度が高くなかったのです。
そのせいで他の現場でバグが頻発していたということはなかったのですが、それでもその最初にテストを求められた現場はそれまでで最も開発〜運用の流れ(DevOps)が洗練されていたという印象です。

品質以前にプロとしての心構え

有形商品を販売する業態であれば、検品作業というのがあります。実際の商品が正しく動作するかどうかを確認する作業です。
これと同じで、コードも「期待する振る舞いを行うかどうかを確認すること」こそがテストです。プログラムもいくつかの部品や機能に分けて考えられるため、単体テストや結合テストがあり、さらにユーザー側に立って確認するE2Eテストなどもあります。

これらをすることで顧客に対してプロフェッショナルの仕事であることを確認したサービスを提供する、というのがエンジニアのプロとして当たり前のことだと気付かされました。最初から抱えるべき心構えであることなので、自身を恥じ入ることになった赤面する経験です。
ぜひこのコンテンツをご覧になった人の中で自分と同じく「後でテストを書けばいいや」という人がいたら、ぜひ一度テストに向き合ってみてください。

テストの種類一覧

以下にエンジニアが実施すべきテストの種類を列挙します。

ユニットテスト(単体テスト)とは

ユニットテストは、ソフトウェアの個々のユニット(単位)やコンポーネントをテストすることに重点を置いています。ユニットとは、1つの関数やクラスを指すことが多いです。目的としては、各単位が分離された状態で意図したとおりに機能することを保証することとなります。
個別の小さな単位でのテストとなるため、テストごとの範囲が狭く、他のコードとの依存関係は考慮しません。

スタブ(代用)やモック(模擬)データを使用することで、擬似的に動作確認を行うため、テスト自体のハンドリングが取りやすいです。まずはここから始めましょう。

統合テスト(結合テスト)

ユニットテストの次のステップです。ユニットテストでテストしたモジュール同士が統合(連結)した状態で期待通りに動作するかを評価します。異なるコンポーネントやシステムが相互作用する際に発生する問題を検出することを目的としています。

データベースや外部コンポーネント、外部ソフトウェアも含めて動作確認をするため、ユニットテストと比べて複雑な環境が必要になり、使うデータもより本番環境に近いデータを利用します。(データベースからDumpしたデータを使ったり、ステージング環境のデータベースを使ったりします)

システムテスト

システム全体の機能を評価し、指定されたビジネス要件を満たしていることを確認する作業です。仕様書や要件定義書がある場合は、付属品としてシステムテストの結果を記入する欄があることもあります。

ユニットテストや統合テストと違い、非機能要件について要件が満たされているかを確認する過程があったり、ドキュメントの整備が含まれていたりします。主にシステムの内部を担当するエンジニアと、ビジネス要件を設定するプロジェクトマネージャーやステークホルダーとのコミュニケーションや合意の一環として実施されます。

受け入れテスト

ソフトウェアがビジネス要件を満たし、エンドユーザーにリリースする準備が整っているかどうかを判断する行程です。請負案件で顧客に提供する際には、顧客側と納品の合意が取れることを前提としたテストを実施します。

QA(品質保証)エンジニアがチームにいる場合は、主に彼ら彼女らが担当するでしょう。この段階でバグや不具合が発見された場合は、開発を担当するエンジニアへの手戻りが発生するため、可能な限り完成品としてのクオリティを担保した状態でテスト依頼をすることをおすすめします。

負荷テスト(パフォーマンステスト)

様々な条件下でのソフトウェアの応答性、速度、安定性をチェックし、負荷がかかった状態でも確実に動作することを確認する行程です。少し前はabコマンド(Apache Benchコマンド。悪用厳禁)を使うことも多かったのですが、Apache JMeterやk6などのツールを使った方法が一般的になってきています。

ユーザビリティの担保をする目的もありますが、予想外の状態におけるシステムはセキュリティリスクが上昇するため、安全性の確認という意味合いもあります。

リグレッションテスト

ソフトウェアに変更を加えた後、新しいコードの変更が既存の機能に悪影響を与えないことを確認する行程です。過去に実行したテストケースを新しいバージョンで再実行し、以前のバージョンと新機能が期待通りに動作することをチェックします。

目的としては、「バグの早期発見」「品質向上」「UXの保護」があります。
リグレッションテストを実施することによって、エンドユーザーの信頼を損なわず安全にリリースできるようになります。

E2Eテスト

E2Eテストは、エンド・トゥー・エンド(End To End)テストの略で、アプリケーションのフローを最初から最後までテストするように設計されたソフトウェアテスト手法です。入力、処理、出力のプロセス全体が円滑に動作し、必要な要件を満たしていることを保証します。

E2Eテストの主な目的は、実際のシナリオをシミュレートし、テスト対象のシステムがすべての関連システムと正しく相互作用し、期待される結果を生み出すことを検証することです。
つまり、エンドユーザーの代わりにエンドユーザーとして振る舞うことで、より現実的なUXを追体験しながらテストできます。

有名なE2EテストフレームワークはPlaywrightやCypress、Autifyなどがあります。

プログラミングにおいて、なぜテストが必要なのか

我々がなぜテストを実行するのか、疑問に感じることもあるでしょう。簡単な関数やクラス、設計の場合は「これをテストする必要があるのだろうか」と避けてしまう状況も頻繁にあります。

しかしながら、その「テストをしなくてもいいのではないか」という習慣や考えが良くないものであると気付くときには、すでに何か大きな障害が発生したときなのです。(特に自分が引き起こしたものなら衝撃も大きいでしょう)

何よりも「自分を信じてはいけない」という前提をもとに、自分自身のためにテストを実施するべきですが、それ以外にも対外的に以下のような意味合いがあります。

ソフトウェア品質の確保

テストは、サービスがエンドユーザーへ届く前に修正できる欠陥やエラーを抽出してくれます。これにより、エンドユーザーの期待に応えられるより品質の高い製品を作ることができます。

どうしても突破できない認証や未実装のまま放置されたボタンなどは、自社製品の信頼に大きく影響するため、こういったバグは早期発見されなくてはなりません。

手戻りコスト削減

開発プロセスの早い段階で不具合を発見・修正することは、ソフトウェアがデプロイされた後に修正するよりも、多くの場合コストが低く済みます。リリースプロセスを再度繰り返したり、なぜその不具合を引き起こしたかのドキュメントをまとめる前に修正するべきです。

ユーザー満足度の向上

よくテストされたソフトウェアは、ユーザー満足度の向上と製品への信頼につながります。「いつ使ってもきちんと期待通り動作する」ことは、この上なく大切な良いサービスの条件となります。

セキュリティの担保

特定のアプリケーション(医療用や自動車用ソフトウェアなど)では、ソフトウェアの不具合が実害につながるケースもあります。人命や財産に影響を与える可能性があるサービスに対するテストは、より厳しい条件のもとでテストを実施する必要があります。(もちろん他のタイプのアプリケーションでも厳しくすべき場合が多いです)

ユーザーが入力する項目に対してありえない数値を入れたり、リクエストの際に過大なデータ量を送信したりすることで、アプリケーションの耐久性を知っておくことで、前もって適切な処理を施すことが可能となります。

アップデート促進

十分にテストされたコードベースがあれば、変更によって生じる混乱を迅速に特定できるため、安心して変更や追加などの作業ができます。
これは新しくプロジェクトに参加したチームメンバーに対して特に有効です。最初は恐る恐るコードの修正を手伝う状況であったとしても、テストが通らないと分かれば、少なくとも自分のコードの何かが悪影響を及ぼしていることを知ることができます。

そういった意味で、テストはエンジニアにとって情報伝達手段として利用できます。「ユーザーはこういった値を入力する可能性がある」「この関数の引数はおおむねこういった値が来る」と理解しておけば、コードに対するキャッチアップを早めることができます。

テストは習慣にしておこう

まとめると、テストはソフトウェア開発に不可欠な要素であり、堅牢で信頼性の高い高品質のソフトウェアを確実に提供するための方法です。テストなしでは、ソフトウェアが意図した目的に適合しているかどうかを判断する客観的な方法はないと思って良いです。

「pushする前に必ず単体テストが走らせる」「ビルド時に統合テストを行う」「ステージングで自動化されたE2Eテストが実施される」など、自分の作業の合間に挟み込むことで習慣化へとつなげることができます。
習慣化が進んでいけば、新しいコードを追加した際、最初にすることがテストを書くことになるので(TDDを採用していれば最初にテストを書きますが)、自分のコードへの信頼性が高まります。

一年後の自分に過去の自分を褒めてあげられるよう、テストを書き続けて習慣化していきましょう。

関連するコンテンツ