時には、他の開発者が書いたコードの単体テストケースを書くことになります。開発者が何をしようとしているか(ビジネスの部分)が本当にわからない場合があり、テストケースを操作して緑色の線を取得するだけです。これらのことは業界では普通ですか?
通常の傾向は何ですか?開発者は自分で書いたコードの単体テストケースを書くことになっていますか?
時には、他の開発者が書いたコードの単体テストケースを書くことになります。開発者が何をしようとしているか(ビジネスの部分)が本当にわからない場合があり、テストケースを操作して緑色の線を取得するだけです。これらのことは業界では普通ですか?
通常の傾向は何ですか?開発者は自分で書いたコードの単体テストケースを書くことになっていますか?
回答:
このブログ投稿「グレートユニットテストの作成:ベストプラクティスとワーストプラクティス」をお読みください。
しかし、ウェブには無数の人がいます。
あなたの質問に直接答えて...
そして、あなたの質問を書いたテストの記述方法はまったく間違っています!!
このアプローチにより、単体テストは価値がなくなります。
一部の実際のアクションが意図したとおりに機能しない場合は、ユニットテストを失敗させる必要があります。そうしないと、テストするコードの前にテストを書くことさえできれば、機能していない煙アラームを持っているようなものです。
関数が何をするのかわからない場合、そのための単体テストを書くことはできません。あなたが知っているすべてのために、それはそれが期待されることさえしません。最初に何をすべきかを知る必要があります。次に、テストを記述します。
現実の世界では、他の誰かのコードの単体テストを書くことはまったく普通です。確かに、元の開発者はすでにこれを行っているはずですが、多くの場合、これが行われなかったレガシーコードを受け取ります。ちなみに、そのレガシーコードが数十年前に遠く、遠くの銀河から来たのか、同僚が先週チェックしたのか、今日書いたのかは関係ありません。レガシーコードはテストなしのコードです
自問してください:なぜ単体テストを書くのですか?グリーン化は明らかに目的を達成するための単なる手段であり、最終的な目標はテスト対象のコードに関する主張を証明または反証することです。
浮動小数点数の平方根を計算するメソッドがあるとします。Javaでは、インターフェースは次のように定義します。
public double squareRoot(double number);
実装を書いたかどうか、他の誰かが書いたかどうかは関係ありません。squareRootのいくつかのプロパティをアサートする必要があります。
したがって、これらを個別のテストとして書き始めます。
@Test
public void canFindSimpleRoot() {
assertEquals(2, squareRoot(4), epsilon);
}
エラー:このテストは既に失敗しています:
java.lang.AssertionError: Use assertEquals(expected, actual, delta) to compare floating-point numbers
浮動小数点演算を忘れました。OK、あなたは紹介double epsilon=0.01
して行きます:
@Test
public void canFindSimpleRootToEpsilonPrecision() {
assertEquals(2, squareRoot(4), epsilon);
}
そして、他のテストを追加します:最後に
@Test
@ExpectedException(IllegalArgumentException.class)
public void throwsExceptionOnNegativeInput() {
assertEquals(-1, squareRoot(-1), epsilon);
}
おっと、再び:
java.lang.AssertionError: expected:<-1.0> but was:<NaN>
テストする必要があります。
@Test
public void returnsNaNOnNegativeInput() {
assertEquals(Double.NaN, squareRoot(-1), epsilon);
}
ここで何をしましたか?メソッドの動作についていくつかの仮定から始めて、すべてが真実ではないことがわかりました。次に、テストスイートGreenを作成し、修正された仮定に従ってメソッドが動作することを証明します。これで、このコードのクライアントはこの動作に依存できます。誰かが実際のsquareRootの実装を他の何か、たとえばNaNを返す代わりに実際に例外をスローしたものと交換した場合、テストはこれをすぐにキャッチします。
この例は簡単ですが、多くの場合、実際に何をするのかが不明な大きなコードを継承します。その場合、通常はコードの周りにテストハーネスを配置します。コードがどのように動作するかについてのいくつかの基本的な前提から始め、それらの単体テストを作成し、テストします。緑の場合、良い、もっとテストを書いてください。赤の場合、仕様に対して保持できるアサーションが失敗しています。レガシーコードにバグがあるのかもしれません。たぶん、この特定の入力についての仕様は不明です。たぶん、あなたは仕様を持っていません。その場合、予期しない動作を文書化するようにテストを書き直してください。
@Test
public void throwsNoExceptionOnNegativeInput() {
assertNotNull(squareRoot(-1)); // Shouldn't this fail?
}
時間が経つにつれて、コードが実際にどのように動作し、コード化された仕様の一種になるかを文書化するテストハーネスになります。レガシコードを変更したり、他のコードに置き換えたい場合は、テストハーネスを使用して、新しいコードが同じように動作すること、または新しいコードが期待され制御された方法で異なる動作をすることを確認します(たとえば、実際に修正が期待されるバグを修正します)。このハーネスは初日に完全である必要はありません。実際、不完全なハーネスを使用する方が、ハーネスをまったく使用しないよりもほとんど常に優れています。ハーネスがあると、クライアントコードをより簡単に記述できるようになり、何かを変更したときにどこで壊れるのか、最終的にどこで壊れたのかがわかります。
フォームの必須フィールドに入力するのと同じように、ユニットテストを書く必要があるという考え方から抜け出そうとする必要があります。そして、赤い線を緑にするためだけに単体テストを書くべきではありません。単体テストは敵ではなく、単体テストは友人です。
テストケース(プリンター用)を書くとき、私は各小さなコンポーネントを考えようとします。たとえば、スキャナーに、どのコマンドが(pjl printer-job-languageで)使用するか、機能のすべてのビットをテストするために何を書くことができるか、と言いましょう....
私は主要なコンポーネントごとにそれをしようとしていますが、ソフトウェアに関してはハードウェアではなく、各メソッド/機能を調べて境界などを確認したいです。