ユニットテスト

2014年5月5日

ユニットテストは、ソフトウェア開発においてよく話題になり、私がプログラムを書いている間ずっと馴染みのある用語です。しかし、ほとんどのソフトウェア開発用語と同様に、その定義は非常に曖昧で、人々が実際よりも厳密に定義されていると考えている場合に、混乱がよく起こりうると私は考えています。[1]

以前にもユニットテストを十分にやってきましたが、決定的な露出は、Kent Beckと一緒に仕事を始めてXunitファミリーのユニットテストツールを使用したときでした。(実際、このスタイルのテストの良い用語は「xunitテスト」かもしれないと時々思います。)ユニットテストは、エクストリームプログラミング(XP)の象徴的な活動にもなり、すぐにテスト駆動開発につながりました。

XPでのユニットテストの使用については、初期の頃から定義に関する懸念がありました。 usenetディスカッショングループでの議論で、私たちXPerが「ユニットテスト」という用語を誤用しているとしてテストの専門家から叱責されたことをはっきりと覚えています。彼に彼の定義を尋ねると、彼は「私のトレーニングコースの最初の朝には、ユニットテストの24種類の定義をカバーします」のような答えを返しました。

バリエーションはありますが、いくつかの共通要素があります。まず、ユニットテストはソフトウェアシステムの小さな部分に焦点を当てた低レベルのものであるという概念があります。第二に、ユニットテストは通常、今日ではプログラマー自身が通常のツールを使用して記述しています。唯一の違いは、何らかのユニットテストフレームワークの使用です[2]。第三に、ユニットテストは他の種類のテストよりも大幅に高速であることが期待されています。

いくつかの共通要素がありますが、違いもあります。一つの違いは、人々がユニットとみなすものです。オブジェクト指向設計ではクラスをユニットとして扱う傾向があり、手続き型または関数型アプローチでは単一の関数をユニットと見なす場合があります。しかし実際には状況次第です。チームは、システムの理解とテストの目的でユニットとして意味をなすものを決定します。私はユニットをクラスとする概念から始めますが、密接に関連するクラスの束を単一のユニットとして扱うことがよくあります。まれに、クラス内のメソッドのサブセットをユニットとして扱うことがあります。どのように定義しても、実際には問題ではありません。

孤独か社交的か?

より重要な区別は、テストしているユニットが社交的であるべきか、孤独であるべきかということです[3]。注文クラスの価格メソッドをテストしていると想像してください。価格メソッドは、商品クラスと顧客クラスの一部の関数を呼び出す必要があります。ユニットテストを孤独にしたい場合は、ここでは実際の商品クラスや顧客クラスを使用したくありません。顧客クラスの障害によって注文クラスのテストが失敗する可能性があるからです。代わりに、コラボレーターにはテストダブルを使用します。

しかし、すべてのユニットテスターが孤独なユニットテストを使用しているわけではありません。実際、1990年代にxunitテストが始まったとき、コラボレーターとの通信が面倒な場合(リモートクレジットカード認証システムなど)を除いて、孤独になろうとはしませんでした。隣接するテストが失敗した場合でも、実際の障害を追跡するのが難しいとは感じませんでした。したがって、テストが社交的になることを許可しても、実際には問題にはつながらないと感じました。

実際、社交的なユニットテストを使用することは、私たちが「ユニットテスト」という用語を使用したことで批判された理由の一つでした。これらのテストは単一ユニットの動作のテストであるため、「ユニットテスト」という用語は適切だと思います。そのユニット以外はすべて正常に機能すると仮定してテストを記述します。

2000年代にxunitテストがより普及するにつれて、少なくとも一部の人々にとっては孤独なテストの概念が戻ってきました。モックオブジェクトとモックをサポートするフレームワークの台頭が見られました。私がクラシックとモックイストスタイルと呼ぶ2つのスタイルのxunitテストが開発されました。2つのスタイルの違いの1つは、モックイストが孤独なユニットテストを主張するのに対し、クラシックは社交的なテストを好むことです。今日、私は両方のスタイルのxunitテスターを知っており、尊敬しています(個人的には私はクラシックスタイルを維持しています)。

私のような古典的なテスターでさえ、厄介なコラボレーションがある場合はテストダブルを使用します。これらは、リモートサービスと通信する際の非決定性を除去するために非常に貴重です。実際、一部のクラシックxunitテスターは、データベースやファイルシステムなどの外部リソースとのコラボレーションはすべてダブルを使用する必要があると主張しています。これは、一部には非決定性のリスクによるものであり、一部には速度によるものです。これは有用なガイドラインだと思いますが、外部リソースにダブルを使用することを絶対的なルールとしては扱いません。リソースとの通信が安定していて十分に高速であれば、ユニットテストでそれを実行しない理由はありません。

速度

ユニットテストの共通の特性(範囲が狭い、プログラマー自身が行う、高速)は、プログラミング時に非常に頻繁に実行できることを意味します。実際、これはSelfTestingCodeの重要な特性の1つです。この状況では、プログラマーはコードを変更するたびにユニットテストを実行します。コンパイルする価値のあるコードがある場合は、1分に数回ユニットテストを実行することがあります。これは、誤って何かを壊してしまった場合に、すぐにそれを知りたいからです。最後の変更で欠陥が発生した場合、探す場所があまりないため、バグを見つけやすくなります。

ユニットテストを非常に頻繁に実行する場合、すべてのユニットテストを実行する必要はありません。通常、現在作業しているコードの部分で動作しているテストのみを実行する必要があります。通常どおり、テストの深さとテストスイートの実行にかかる時間との間でトレードオフが発生します。コンパイルを考えるたびに実行するものなので、このスイートをコンパイルスイートと呼びます。Rubyのようなインタプリタ言語でも同様です。

継続的インテグレーションを使用している場合は、その一部としてテストスイートを実行する必要があります。このスイート(コミットスイートと呼びます)には、すべてのユニットテストを含めるのが一般的です。また、いくつかのブロードスタックテストも含まれる場合があります。プログラマーとして、このコミットスイートを1日に数回、特にバージョン管理への共有コミットの前、また休憩を取る場合や会議に行く必要がある場合など、機会があればいつでも実行する必要があります。コミットスイートが速ければ速いほど、実行頻度が高くなります。[4]

ユニットテストとテストスイートの速度に関する基準は、人によって異なります。David Heinemeier Hanssonは、数秒かかるコンパイルスイートと数分かかるコミットスイートに満足しています。Gary Bernhardtは、耐えられないほど遅いと感じており、約300msのコンパイルスイートを主張しており、Dan Bodartは、コミットスイートが10秒を超えることを望んでいません。

ここには絶対的な答えはないと思います。個人的には、1秒未満のコンパイルスイートと数秒のコンパイルスイートの違いには気づきません。 Kent Beckの経験則では、コミットスイートは10分以内に実行される必要があると言っています。しかし、重要な点は、テストスイートが十分に頻繁に実行しても落胆しない程度に高速に実行される必要があるということです。そして、十分に頻繁とは、バグを検出した場合に、迅速に見つけられるように、調べる必要のある作業量が十分に少ない場合です。

注釈

1: 統合テストのエントリで、名前の歴史的ルーツについて少し書きました

2: 「最近」と言うのは、これがXPによって変わったことだからです。世紀末の議論では、XPerは、プログラマーは自分のコードをテストすべきではないという一般的な見解であったため、このことで強く批判されました。一部のショップには、以前に開発者が書いたコードのユニットテストを書くことを仕事とする専門のユニットテスターがいました。これの理由には、人々が自分のコードをテストすることに概念的な盲目性を持っていること、プログラマーが優れたテスターではないこと、開発者とテスターの間に敵対的な関係を持つことが良いことなどが含まれていました。 XPerの見解は、プログラマーは少なくともユニットレベルで効果的なテスターになることを学ぶことができ、別のグループを関与させると、テストが与えるフィードバックループが絶望的に遅くなると言うものでした。 Xunitはここで不可欠な役割を果たしました。テストを記述するプログラマーの摩擦を最小限に抑えるように特別に設計されました。

4: コミットスイートの実行に要する時間よりも長い時間がかかるが有用なテストがある場合は、デプロイメントパイプラインを構築し、パイプラインの後段に遅いテストを配置する必要があります。

改訂

2014年10月24日に、Fieldの社交的/孤独な語彙についての言及を含めるように更新されました。

2017年3月9日に、孤独/社交的な用語を区別を説明するための主要な方法とし、「コラボレーターの分離」(テストフィクスチャの変更を互いに分離することとの混同のため)という用語の使用を削除するように更新されました。