テスト駆動開発の実践


詳細
最近テスト駆動開発を学んで、本「テスト駆動開発の芸術」も買って、個人的に利益を得たと感じています.
TDDの原則は簡単です.
コードは未合格のテストを修復するためだけです
まず本の中の簡単な例から勉強します.
大体の需要は以下の通りである:サブシステムを開発する必要があり、サブシステムはメールテンプレート機能をサポートし、使用者はマウスを数回クリックするだけで従業員に個性的なメールを送信することができる.では、TDDでこのシステムを開発するにはどうすればいいのでしょうか.まず需要を分解し、より小さく、より具体的にしなければならない.テンプレートサブシステムを次のテストに分解できます.
1.変数のないテンプレートで、レンダリング前後の内容は変更されません.
2.レンダリング後の変数を応答値に置き換える変数を含むテンプレート.
3.複数の変数を含むテンプレートで、レンダリング後の変数を対応する値に置き換える必要があります.
4.テンプレートに存在しない変数値は無視されます.
テストに変換してみました.
1.テンプレート「Hello,${name}」を評価し、nameの値がReaderの場合、結果はHello,Readerであるべきである.
2.テンプレート「${greeting},${name}」を評価し、2つの変数値はそれぞれ「Hello」「Reader」であり、結果はHello,Readerであるべきである.
3.テンプレート「Hello,${name}」を評価し、変数に対応する値がない場合は例外を放出します.
ちょっと待って...
私たちの最初のTDD開発を始めます.IDE、Just now--.
失敗したテストを書きます.

public class TestTemplate {

	@Test
	public void oneVariable(){
		Template template = new Template("Hello,${name}");
		template.set("name","Reader");
		String expected = "Hello,Reader";
		String actual = template.execute();
		assertEquals(expected, actual);
	}
}

バッグを導入するときにつけるのを忘れないでください.
import static org.junit.Assert.*;
それ以外の場合、assertEqualsは構文エラーを報告します.
この时、IDEはきっと待ちきれないで私达にTemplate类がまったく存在しないことを教えて、私达はIDEを利用して相応のcodeを生成することができます.
これは、次のコード・リストがあるはずです.

public class Template {

	public Template(String string) {
	}

	public void set(String string, String string2) {
		
	}

	public String execute() {
		return null;
	}

}

はい、これから何をしますか.もちろん、実行ユニットのテストです.このとき、私たちの結果は失敗したに違いありません.私たちは実装を書いていないからです.
次は?仕事が来て、テストを走らせます!
どうやってテストを合格させますか?覚えておいてください.私たちのコードの目的はテストを通過させるためだけです.あまり考えなくてもいいです.あなたの実現方法は何なのか分かりません.次の実現方法を試して、テストを通過させることができるかどうかを見てみましょう.

public class Template {

	...// , 

	public String execute() {
		return "Hello,Reader";
	}

}

はい、前のテストを実行します.このとき、緑の棒が現れ、テストが合格したことを示します.
もちろん、これは投機的だと言えるが、テスト駆動開発の原則は失敗したテストを修復することである.ハードコーディングが存在するため、コードをクリーンアップする必要があるため、この実装は不十分であることは明らかです.
2つ目のテストを追加します.

@Test
	public void differentTemplate(){
		Template template = new Template("Hi,${name}");
		template.set("name","Reader");
		String expected = "Hi,Reader";
		String actual = template.execute();
		assertEquals(expected, actual);
		
	}

実行に失敗したのは、明らかに時間が私たちの実現を修正したからです.つまり、テンプレートを何らかの方法で解析しなければなりません.
擬似インプリメンテーションを引き続き使用します.
まず、変数値とテンプレートファイルを保存し、evaluateメソッドでテンプレートテキストの変数を変数値で置き換えます.実装コードは次のとおりです.

public class Template {

	private String templateText;
	private String variableValue;
	public Template(String templateText) {
		this.templateText = templateText;
	}

	public void set(String variable, String value) {
		this.variableValue = value;
	}

	public String execute() {
		return this.templateText.replaceAll("\\$\\{name\\}", variableValue);
	}

}

これはあなたが*弊害を感じているかもしれません.私たちは依然としてハードコーディングを持っているので、${name}の正規表現を探しています.しかし、これは*弊ではありません.私たちは小さなステップで前進し、覚えていて、小さなステップで前進しなければなりません.
ハードコーディングはどのように解消しますか?テストに複数の変数を追加するのはおそらく最善の消去方法でしょう.
はい、仕事がまた来て、偽の実装を除去して、多変数テストを追加し続けます.テストクラスに次のコードを追加します.

@Test
	public void multipleVariables(){
		Template template = new Template("${one},${two},${three}");
		template.set("one","1");
		template.set("two","2");
		template.set("three","3");
		String expected = "1,2,3";
		String actual = template.execute();
		assertEquals(expected, actual);
	}

テスト、実行、失敗(失敗しなければかえって正常ではありません;-)
コードリストは次のとおりです.

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class Template {

	private Map variables; //store the variables.
	private String templateText;
	public Template(String templateText) {
		variables = new HashMap();
		this.templateText = templateText;
	}

	public void set(String variable, String value) {
		this.variables.put(variable, value);
	}

	public String execute() {
		String result = templateText;
		for(Entry entry:variables.entrySet()){ // iterator the variables.
			String regex = "\\$\\{" + entry.getKey() + "\\}";
			result = result.replaceAll(regex, entry.getValue());
		}
		return result;
	}
	
}

次は私たちのテストコードを実行して、すべての緑の棒を実行して、合格します.
次に、テンプレートに存在しない変数を入力するとどのような効果が得られるかをテストし、テスト例を追加します.

@Test
	public void unknownVariableAreIgnored(){
		Template template = new Template("Hi,${name}");
		template.set("name","Reader");
		template.set("do not exist","Hi"); //this variable is not exist in the template.
		String expected = "Hi,Reader";
		String actual = template.execute();
		assertEquals(expected, actual);
	}

これはテストに合格できると思います.私たちのビジネスコードはもう強くなったので、実行して、確かにすべて実行しました.
次は、テストコードと製品コードが同等に重要であるため、時間再構築です.テストコードのリストを見てみましょう.

public class TestTemplate {

	@Test
	public void oneVariable(){
		Template template = new Template("Hello,${name}");
		template.set("name","Reader");
		String expected = "Hello,Reader";
		String actual = template.execute();
		assertEquals(expected, actual);
	}
	
	@Test
	public void differentTemplate(){
		Template template = new Template("Hi,${name}");
		template.set("name","Reader");
		String expected = "Hi,Reader";
		String actual = template.execute();
		assertEquals(expected, actual);
		
	}
	
	@Test
	public void multipleVariables(){
		Template template = new Template("${one},${two},${three}");
		template.set("one","1");
		template.set("two","2");
		template.set("three","3");
		String expected = "1,2,3";
		String actual = template.execute();
		assertEquals(expected, actual);
	}
	
	@Test
	public void unknownVariableAreIgnored(){
		Template template = new Template("Hi,${name}");
		template.set("name","Reader");
		template.set("do not exist","Hi"); //this variable is not exist in the template.
		String expected = "Hi,Reader";
		String actual = template.execute();
		assertEquals(expected, actual);
	}
}

まずすべてのテストでTemplateオブジェクトが使用されているので、メンバー変数として抽出したほうがいいです.次に、すべてのテスト方法でevaluateメソッドの戻り値を比較対象として比較したほうがいいです.このような繰り返しを解消したほうがいいです.また、最初のテスト、2番目のテスト、最後のテストなどの重複テストを削除するテストコードを振り返って確認する必要があります.また、multipleVariables()のテンプレートファイルをunknownVariableAreIgnored()で使用することもできます.
したがって、冗長性テストを排除し、スタイルを統一したテストコードは以下の通りです.

public class TestTemplate {

	private Template template;
	@Before
	public void setUp(){
		template = new Template("${one},${two},${three}");
		template.set("one","1");
		template.set("two","2");
		template.set("three","3");
	}
	@Test
	public void multipleVariables(){
		String expected = "1,2,3";
		assertTemplateEvaluatesTo(expected);
	}
	
	@Test
	public void unknownVariableAreIgnored(){
		template.set("do not exist","Hi"); //this variable is not exist in the template.
		String expected = "1,2,3";
		assertTemplateEvaluatesTo(expected);
	}
	
	private void assertTemplateEvaluatesTo(String expected){
		assertEquals(expected,template.evaluate());
	}
}

今のテストコードはもっと簡潔になったのではないでしょうか.このように、テストコード自体はより軽快で短く、テストするビジネスロジックに注目します.
次に、テストを書き続け、新しい機能を追加します.現在、テンプレートエンジンには基本的な機能がありますが、次はエラー処理機能の追加を検討する必要があります.しかし、ステップは依然としてこのようにして、循環は漸進的で、一歩一歩、覚えていて、小さなステップで前進します.私たちが機能を改善し続けると、私たちのevaluate()方法はますます肥大化していることがわかります.この時、また再構築の時になりましたが、ユニットテストが保証されているので、青信号を常に点灯させさえすれば、安心して再構築することができます.