サンプルコード
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になることが確認できます。リファクタリングは必要なさそうですから、仕様変更も完了です。