« [TDD の練習(2)] (すっかり出遅れた) 縦書き祭 | トップページ | 新年明けましておめでとうございます »

2008年12月31日 (水)

[TDD の練習(3)] 和暦年月の文字列を検証する

とある掲示板より。
> 号年月(例 H2012)が実在する年月であるかをチェックしたいです。
> 年号は、H=平成 S=昭和のみを対象とします。

質問者は、 旧 VB の IsDate() 関数と互換のメソッドが使えるような実装が出来た、 というところで終わっています。 そのコードは、 「一部省略しております」 とのことで、 文字列を分解する前の文字列長チェックとかは書かかれていません。

で。 こういう検証器、 つまり、 引数が何らかの基準を満たしていたら true、 そうでなければ false を返すというモノは、 テストを書きやすいのでネタにしてみます。
また、 和暦を扱う上で厄介なのは、 境界値の前後をどうするかという仕様の問題ですが、 ここでは IsDate() の挙動に合わせる、 ということにします。

ということで、 いつものようにどんなテストコードを書いていけばいいのかを、 文章で書いてみますので、 ユニットテストに書き下してみてください。

今回は、 VB.NET 2008 + NUnit です。
・ プロジェクト名: IsDateを使ってみる
・ テストクラス: 年月検証器のテスト
・ 製品クラス: 年月検証器 ( +α )
・ 製品に実装するメソッド
Public Shared Function それは実在する年月か (ByVal 元号年月 As String) As Boolean

 

  1. とりあえず、 True が返るはずの適当な引数を渡すテスト。
    このテストをクリア出来るように実装して、 とりあえず呼び出して使えるようにします。
    ※ 実装は、Return True だけでいいです。

  2. ダメな引数を渡すテスト。
    これで、 一応の実装をすることができます。

  3. 境界値を調べるテスト
    和暦でやっかいなのは、 年号が変わるときです。
    仕様では、昭和以降を扱うことになっているので、 昭和と平成の変わり目をみます。

    • (3-1) 平成の始まりは H010108 です。
      H0101 と、 その前の月 H0012 をテストしましょう。

    • (3-2) 昭和の終わりは S640107 です。
      VB の IsDate() に合わせて、 その年の末までは OK とします。
      ※ S6402 も S6412 も実在していることとします。 S6501 は実在しないこととします。


  4. 境界値を調べるテストをもうひとつ。
    昭和の始まりは S011225 です。
    これも VB の IsDate() に合わせてその年の始めまでは OK とします。

  5. 文字列のフォーマットをテストします。
    引数のフォーマットは、 元号の英大文字 + 年二桁 + 月二桁 (合わせて半角5ケタ) のみです。

    • (5-1) 年号が違う文字のとき。

    • (5-2) 長さが違うとき。

    • (5-3) その他の文字のとき。

    • (5-4) Null と空文字。

※ ここまでのテストで、正規表現によるパターンマッチングが実装され、 例外が出て Try ~ Catch が実装された段階で、 あとは IsDate() が誤判定をしないという前提に立てば、 フォーマットの細かい検査をするテストは不要と判断できます。

回答例 ( VB.NET + NUnit 用のソースコード ) はこちら → YearMonthCheckerTests.vb [2KB]
※ cocolog の制約で日本語ファイル名が使えないので、 ファイル名を変えています。

ちゃんと自分で書いてみてから、 見てくださいね f(^^;

そして、 このテストコードをパスするように実装とリファクタリングしたコードは、 こうなりました。


[ 年月検証器.vb ]

Option Explicit On
Option Strict On

Imports System.Globalization
Imports
System.Text.RegularExpressions

Public NotInheritable Class 年月検証器

  Private Sub New()
    '(void)
  End Sub


  ''' <summary>
  ''' 和暦の年月が実在するかどうかを判定します。
  ''' </summary>
  ''' <param name="元号年月">
  ''' 半角5文字の和暦年月です。
  ''' 英大文字 + 年二桁 + 月二桁</param>
  ''' <returns>実在するとき True</returns>
  ''' <remarks>VB の IsDate() 関数と同様に、
  ''' 年号の変わる年はどちらの年号でも OK とします。
  ''' </remarks>
  Public Shared Function それは実在する年月か( _
    ByVal 元号年月 As String) As Boolean

    If (String.IsNullOrEmpty(元号年月)) Then
      Return False
    End If

    If (Not 年月検証器.そのフォーマットは正しいか(元号年月)) Then
      Return False
    End If

    Dim 区切り入り日付 As String _
      = 年月検証器.区切り文字を入れて日付にしろ(元号年月)

    Try
      Return _
        MicrosoftVisualBasicWrapper.IsDate( _
          区切り入り日付)

    Catch ex As _
        System.ArgumentOutOfRangeException
      Return False

    End Try

  End Function

  Private Shared Function そのフォーマットは正しいか(ByVal 元号年月 As String) As Boolean
    Return Regex.IsMatch( _
        元号年月, _
        "^[A-Z][0-9][0-9][0-9][0-9]$")
  End Function

  Private Shared Function 区切り文字を入れて日付にしろ(ByVal 元号年月 As String) As String
    Dim 元号 As String = 元号年月.Substring(0, 1)
    Dim 年 As String = 元号年月.Substring(1, 2)
    Dim 月 As String = 元号年月.Substring(3, 2)

    Return String.Format( _
      CultureInfo.InvariantCulture, _
      "{0}{1}/{2}/01", 元号, 年, 月)
  End Function

End Class



[ MicrosoftVisualBasicWrapper.vb ]

Option Explicit On
Option Strict On

''' <summary>
''' Microsoft.VisualBasic 名前空間は、
''' 廃止されても文句は言えないので、
''' ここに隔離しておく。
''' </summary>
Public NotInheritable Class MicrosoftVisualBasicWrapper

    Private Sub New()
        '(void)
    End Sub

    Public Shared Function IsDate(ByVal expression As Object) As Boolean
        Return Microsoft.VisualBasic.IsDate(expression)
    End Function

End Class

|

« [TDD の練習(2)] (すっかり出遅れた) 縦書き祭 | トップページ | 新年明けましておめでとうございます »

プログラミング」カテゴリの記事

-プログラミング ( わんくま )」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/209349/43581243

この記事へのトラックバック一覧です: [TDD の練習(3)] 和暦年月の文字列を検証する:

» [TDD の練習(4)] フィボナッチ数列の問題 ~ その1 : 数列を生成する [biac の それさえもおそらくは幸せな日々@nifty]
ぴえろっちが教えてくれた Project Euler の問題 ( かってに改題 f(^^; ) より。…いや、 オリジナルを示しておきましょか。 Project Euler .net ~ Problem 2 ( 19 October 2001 )日本語訳: Project Euler ~ Problem 2フィボナッチ... [続きを読む]

受信: 2009年1月12日 (月) 21時43分

« [TDD の練習(2)] (すっかり出遅れた) 縦書き祭 | トップページ | 新年明けましておめでとうございます »