《コードの美しさ》第7章きれいなテストのbad smell


詳細
この章では,2点検索に基づいて,きれいなテストをどのようにすべきかを議論した.
まず原文のやり方を見てみましょう.ここでの議論は,ランダム,性能,配列中の要素の繰返し,nullと入力する場合を省略する.
	public void testBinarySearch() {

		int[] testArray = ...;
		int target = ...;

		int returnValue = Util.binarySearch(testArray, target);

		//  returnValue -1 , target.
		assertTheory1(testArray, target, returnValue);

		//  returnValue 0 , returnValue target.
		assertTheory2(testArray, target, returnValue);

		//  target , -1.
		assertTheory3(testArray, target, returnValue);

		//  testArray n target, binarySearch(testArray,target) n.
		assertTheory4(testArray, target, returnValue);
	}

	private void assertTheory1(int[] testArray, int target, int returnValue) {
		if (returnValue == -1) {
			assertFalse(arrayContainsTarget(testArray, target));
		}
	}

	private void assertTheory2(int[] testArray, int target, int returnValue) {
		if (returnValue >= 0) {
			assertEquals(target, testArray[returnValue]);
		}
	}

	private void assertTheory3(int[] testArray, int target, int returnValue) {
		if (!arrayContainsTarget(testArray, target)) {
			assertEquals(-1, returnValue);
		}
	}

	private void assertTheory4(int[] testArray, int target, int returnValue) {
		assertEquals(getTargetPosition(testArray, target), returnValue);
	}

	private int getTargetPosition(int[] testArray, int target) {
		for (int i = 0; i < testArray.length; i++) {
			if (testArray[i] == target)
				return i;
		}
		return -1;
	}

著者はまずTheory 1,2を検証の手段として確立し,その後Theory 1,2に脆弱性があることを発見し,Theory 3,4を補足してテストグループを形成した.
しかし、このコードをよく研究すると、まだ問題があることがわかりました.
一つの小さな欠陥はTheory 4の定義と実現が一致していないことであり、Theory 4のcode検証にはTheory 4の理論推理が含まれている.
もともとこれも何も起きられないことはありませんが、なぜ二分検索をテストしたのかを最初から振り返ってみましょう.
答え:簡単な検索は間違いにくいが遅いので、スピードの速い二分検索が必要です.
しかし、二分検索はいくつかの中値を求めることに関連していますね.上下限の操作を変えると、間違いやすいので、二分検索をテストする必要があります.
Aha,getTargetPosition自体が二分ルックアップ仕様に適合する単純ルックアップ(性能を除く)であり,その単純さのため,肉眼検査ではその実現が正しいと確信できる.構想が来て、1つの正しい遅い実現で1つの速い実現を検証します.
従来のTheory 1,2,3,4は1つになりましたが、いずれの場合も、2点ルックアップ機能仕様(パフォーマンスを除く)に準拠した単純なルックアップの結果と同じである必要があります.
Refine後のコードは以下の通りです.
	public void testBinarySearch() {

		int[] testArray = new int[10];
		int target = 0;

		int returnValue = Util.binarySearch(testArray, target);

		assertEquals(getTargetPosition(testArray, target), returnValue);	

	}


	private int getTargetPosition(int[] testArray, int target) {
		for (int i = 0; i < testArray.length; i++) {
			if (testArray[i] == target)
				return i;
		}
		return -1;
	}

うん、codeが少なくなって、もっと簡潔できれいになりました.I like it.