サンプルコード
TDDではおなじみのFizzBuzzです。FizzBuzz問題をご存知ない方は、Wikipediaの記事などを参照してください。バグを埋め込むために、わざとswitch文を使った変な実装にしてあります。
using NUnit.Framework;
using CsTdd04.FizzBuzz;
namespace CsTdd04.FizzBuzzTest {
[TestFixture]
public class FizzBuzzerTest {
[TestCase(1, "1")]
[TestCase(3, "Fizz")]
[TestCase(5, "Buzz")]
[TestCase(6, "Fizz")]
[TestCase(9, "Fizz")]
[TestCase(10, "Buzz")]
[TestCase(12, "Buzz")]
[TestCase(15, "FizzBuzz")]
public void SayTest(int n, string expected) {
Assert.That((new FizzBuzzer()).Say(n), Is.EqualTo(expected));
}
}
}
namespace CsTdd04.FizzBuzz {
public class FizzBuzzer {
public string Say(int n) {
switch (n) {
case 3:
case 6:
case 9:
return "Fizz";
case 5:
case 10:
case 12:
return "Buzz";
case 15:
return "FizzBuzz";
default:
return n.ToString();
}
}
}
}
仕様追加
エライ人「あ、b君、b君! 昨日の仕様だけどね」
b君「なんでしょう?」
エライ人「言い忘れたけど。あれって、1から始まるんだよね…」
b君「そうです」
エライ人「じゃ、当然だけどゼロのときは例外にしてね」
b君「はぁ」(そんな呼び出しするわけないじゃん…)
引数がゼロの時(ニュアンスを汲み取ると負の時もでしょう)、文字列を返さずに例外を投げて欲しいという仕様追加です。
作業に取り掛かる前に、オールGREENを確認します。そうしたら、追加された仕様を表現するテストケースを新しく書きます。ここで出て欲しい例外は、ArgumentOutOfRangeExceptionですね。
//仕様追加: 0以下のときは、例外を出す。
[TestCase]
public void SayTest_ExceptionWhenZero() {
Assert.Throws<System.ArgumentOutOfRangeException>(() => (new FizzBuzzer()).Say(0));
}
テストコードを追加したら、予想通りのREDになることを必ず確認します。
CsTdd04.FizzBuzzTest.FizzBuzzerTest.SayTest_ExceptionWhenZero(): Expected: <System.ArgumentOutOfRangeException> But was: null
REDになることが確認できたら、製品コードを修正します。
public string Say(int n) {
if (n <= 0) // ←追加
throw new System.ArgumentOutOfRangeException(); // ←追加
switch (n) {
case 3:
// 以下略
これでオールGREENになることを確認します。特にリファクタリングは必要なさそうですから、これで仕様追加は完了です。
仕様変更
レビュアー「あ、bさん! 昨日やった仕様書ですけど」
b君「なんかありました?」
レビュアー「見落としてたんですが、15の倍数のときはFizzとBuzzの間にスペースが入るんです」
b君「もう実装しちゃったよ~」
レビュアー「そういわれても、それが正しい仕様なんで、お願いしますよ」
b君「もぉ、しょうがないなぁ~」(まぁ、即座に直るけどねっ)
引数が3の倍数かつ5の倍数のときは"FizzBuzz"を返すという仕様でしたが、"Fizz Buzz"(間に半角スペースが入る)に変えてほしいという仕様変更です。
メソッドの外部設計を変更する場合には、対応するテストケースが必ず存在するはずです。まず、そのテストケースを探します。
[TestCase(15, "FizzBuzz")]
新しい仕様に従って、テストケースを修正します。
[TestCase(15, "Fizz Buzz")] //スペースが入るのが正しい
テストコードを変更したら、予想通りのREDになることを必ず確認します。
CsTdd04.FizzBuzzTest.FizzBuzzerTest.SayTest(15,"Fizz Buzz"): Expected string length 9 but was 8. Strings differ at index 4. Expected: "Fizz Buzz" But was: "FizzBuzz" ---------------^
REDになることが確認できたので、製品コードを修正します。
public string Say(int n) {
// 略
case 15:
return "Fizz Buzz"; // ←変更
// 略
これでオールGREENになることが確認できます。リファクタリングは必要なさそうですから、仕様変更も完了です。
