読者です 読者をやめる 読者になる 読者になる

miso_soup3 Blog

主に ASP.NET 関連について書いています。

Tips 単体テスト可読性UP方法

ASP.NET Fall 2012 Update が気になるところですが…
単体テストについてです。

可読性UP!

expect(予想値)と、actual (結果値) を明確にして書くと、
テストがわかりやすくなるとよく言われますが、

もう一歩進んで、

  • expect(予想値)
  • actual (結果値)
  • もう1つ、実行メソッド

これら3つの距離を視覚的に近くして、
そして更に、

  • 関連のあるテストケースを近くに集める

と可読性がUPします!

わかりにくい例

例えば下のようなメソッドの単体テストを書く場合は、

//テスト対象メソッド
DateTime? ToNullableDate(string input);

こんな書き方があると思います。

//一般的な文字列から日付への変換テスト
{
  String input = "2012/03/01";
  DateTime? expect = new DateTime(2012, 3, 1);
  DateTime? actual = DateHelper.ToNullableDate(input);

  Assert.AreEqual(expect, actual);
}
//空文字が指定されたら、Null を返しているかのテスト
{
  String input = String.Empty;
  DateTime? expect = null;
  DateTime? actual = DateHelper.ToNullableDate(input);

  Assert.AreEqual(expect, actual);
}

綺麗に書かれているのですが、この書き方は連続して書かれると、
わかりにくくなる、という欠点があります。
なぜかというと、2つのテストケースが結構離れているかからです。

実行メソッドの仕様が、複数のテストケースによって把握できるものである場合、
この方法はちょっとわかりにくくなります。

他の方法である、Nunit の TestCase を使っても・・・↓

//ToNullableDate のテストケース
object[] toNullableDate_TestCase = new object[]
  {
    new object[] { "2012/03/01", new DateTime(2012, 3, 1)},
    new object[] { String.Empty, null }
  };

[Test]
[TestCaseSource("toNullableDate_TestCase")]
public void ToNullableDate_Test(String input, DateTime? expect)
{
  DateTime? actual = DateHelper.ToNullableDate(input);
  Assert.AreEqual(expect, actual);
}

テストケースが並べられ良い感じになりましたが、
Nunit の TestCaseSource には、テストケースの値がどういう値なのか、わかりにくい
という欠点があります。

わかりやすい書き方

デリゲートと、Nunit の That 記法を使って、
3つの距離を小さくして、テストケースをまとめると・・・

Func<String, DateTime?> execute =
  (input) => DateHelper.ToNullableDate(input);

Assert.That(execute("2012/03/25"), Is.EqualTo(new DateTime(2012, 3, 25)));
Assert.That(execute(String.Empty), Is.Null);

Assert.That( () => execute("invalidValue"), Throws.Exception);

どうでしょう!?
わかりやすくなりました!?