ユニットテストとは何か、そしてそれはなぜ重要なのか?
ユニットテストとは、あなたがコーディングした関数が期待通りに動作することを確認するために、テストを作成して自動的に実行するプロセスです。より多くの作業のように見えるかもしれませんが、実際にはバグが発生する前にそれを潰すための予防措置を講じることに関するものです。
ユニットテストとは何ですか?
「ユニット」は、あなたのアプリでの最小限のソフトウェアコンポーネント(つまり、関数、クラス、またはコンポーネント)です。個々のユニットテストは、アプリのコアコンポーネントが期待通りに動作していることを確認し、コードの1つの領域への将来のコミットが別の領域のコードを壊さないことを保証します。もし壊れた場合、あなたの新しいコードまたは古いコード(または不適切に書かれた/古くなったテスト)にバグがある可能性があります。
ユニットテストの目的は明らかです。バグ、特に統合から生じるバグを減らすことです。開発者はローカルで何も問題がないと思っていても、コードをコミットした後に別のコミットがアプリを壊してしまったことに気づくかもしれません。ユニットテストは、これらの欠陥のいくつかを問題になる前に捕捉するのに役立ち、また、自動化された継続的インテグレーションパイプラインと組み合わせることで、毎日のビルドが常に適切に機能することを確実にすることができます。
ユニットテストは小さなコードの断片に限らず、複数の他の関数を利用する大きなコンポーネントのユニットテストも可能です。これにより、エラーをより効果的に追跡することができます---エラーは大きなコンポーネントオブジェクトのメソッドにあるのか、それとも利用している他のコンポーネントのどれかにあるのか?
単体テストは重要ですが、それだけが行うべきテストではありません。エンドツーエンドのUIテストや手動による人間のレビューを実施することで、単体テストでは見逃されがちな論理バグを数多く発見できます。すべてのユニットが期待通りに動作している場合でもです。
ユニットテストはクリーンなコードベースにつながる
レガシーコードベースの主な問題の一つは、恐竜のようなコードです。あまりにも古くて、ほとんどブラックボックスのようになっているため、どのように動いているのか全くわからないことがありますが、なぜか動いています。そのため、すべてが壊れるのが怖くてリファクタリングしたくないという気持ちがあります。
ある意味、ユニットテストを書くときは、それがドキュメントを書くことになります。完全なマニュアルを書く必要はないかもしれませんが、常に2つのことを定義することになります:関数に渡すものと、関数が返すものです。これは、APIスキーマを定義するのと似ています。この2つの情報があれば、関数が何をするのか、そしてそれをアプリに統合する方法が明確になります。もちろん、ユニットテストは既存のレガシーコードベースの問題を解決するものではありませんが、最初からこの種の恐竜コードを書くことを防いでくれます。
しばしば、テストする実際の関数の前にテストを書くことができます。関数が何をする必要があるかを知っていれば、テストを先に書くことで、コードの最終結果や、コードが何に責任を持っているかを考えさせられます。
もしこのユニットテストの効果が気に入ったのであれば、TypeScriptにも興味があるかもしれません。TypeScriptはJavaScriptのコンパイルされたスーパーセットで、強い型付けを可能にします。ユニットテストを書くことは依然として重要ですが、コーディング中に関数が渡す型と受け取る型を知ることは非常に便利な機能です。
ユニットテストの実行方法
さまざまなユニットテストフレームワークがあり、最終的に使用するものはテストしている言語によって異なります。ただし、それらの動作を示すために、新しいReactアプリケーションのデフォルトとなっているJavaScriptテストフレームワークであるJestを使用します。
単体テストは通常、三つの段階から構成されています:
- 単位をテストするためにデータが準備される場所を整えます。データを取得する必要がある場合、複雑なオブジェクトを構築するか、単にいくつかの設定を行う場合は、これを最初に行います。
- アクションを実行し、ユニットが呼び出され、応答が記録されます。
- アサート、ここがテストの大部分が行われる場所です。ここでは、に基づいてブール演算を書くことができます。
いずれかのアサーションが失敗した場合、そのユニットはテストに失敗したことになり、何が問題だったのか、期待した結果、実際に返されたものについての詳細なログとスタックトレースを取得します。
Jest にはさまざまなマッチャーがあり、クイックでシンプルなアサーションを行うことができます。たとえば、次のような2つの数字を足すだけの関数があるとしましょう:
function doSomeMath(a, b) {
return a + b;
}
次の文でこの関数をテストできます:
test('Expect math to work', () => {
expect(doSomeMath(1, 1)).toBe(2);
});
通常、これはfunctionName.test.jsの下に関数と共に保存されます。Jestはテストを実行する際に自動的にこれらのファイルを探します。
.toBe() 関数はマッチャーで、今回は基本的な等価性をチェックします。他にも多くのマッチャーがあり、例えば.toBeEqual()はオブジェクトの等価性をチェックし、.toContain()は配列の内容をチェックします。Jestのドキュメントを通じて、サポートされているマッチャーの完全なリストを読むことができます。
