[TDD の練習(3)] 和暦年月の文字列を検証する
とある掲示板より。
> 号年月(例 H2012)が実在する年月であるかをチェックしたいです。
> 年号は、H=平成 S=昭和のみを対象とします。
質問者は、 旧 VB の IsDate() 関数と互換のメソッドが使えるような実装が出来た、 というところで終わっています。 そのコードは、 「一部省略しております」 とのことで、 文字列を分解する前の文字列長チェックとかは書かかれていません。
で。 こういう検証器、 つまり、 引数が何らかの基準を満たしていたら true、 そうでなければ false を返すというモノは、 テストを書きやすいのでネタにしてみます。
また、 和暦を扱う上で厄介なのは、 境界値の前後をどうするかという仕様の問題ですが、 ここでは IsDate() の挙動に合わせる、 ということにします。
ということで、 いつものようにどんなテストコードを書いていけばいいのかを、 文章で書いてみますので、 ユニットテストに書き下してみてください。
今回は、 VB.NET 2008 + NUnit です。
・ プロジェクト名: IsDateを使ってみる
・ テストクラス: 年月検証器のテスト
・ 製品クラス: 年月検証器 ( +α )
・ 製品に実装するメソッドPublic Shared Function それは実在する年月か (ByVal 元号年月 As String) As Boolean
- とりあえず、 True が返るはずの適当な引数を渡すテスト。
このテストをクリア出来るように実装して、 とりあえず呼び出して使えるようにします。
※ 実装は、Return True だけでいいです。
- ダメな引数を渡すテスト。
これで、 一応の実装をすることができます。
- 境界値を調べるテスト
和暦でやっかいなのは、 年号が変わるときです。
仕様では、昭和以降を扱うことになっているので、 昭和と平成の変わり目をみます。- (3-1) 平成の始まりは H010108 です。
H0101 と、 その前の月 H0012 をテストしましょう。
- (3-2) 昭和の終わりは S640107 です。
VB の IsDate() に合わせて、 その年の末までは OK とします。
※ S6402 も S6412 も実在していることとします。 S6501 は実在しないこととします。
- (3-1) 平成の始まりは H010108 です。
- 境界値を調べるテストをもうひとつ。
昭和の始まりは S011225 です。
これも VB の IsDate() に合わせてその年の始めまでは OK とします。
- 文字列のフォーマットをテストします。
引数のフォーマットは、 元号の英大文字 + 年二桁 + 月二桁 (合わせて半角5ケタ) のみです。- (5-1) 年号が違う文字のとき。
- (5-2) 長さが違うとき。
- (5-3) その他の文字のとき。
- (5-4) Null と空文字。
- (5-1) 年号が違う文字のとき。
※ ここまでのテストで、正規表現によるパターンマッチングが実装され、 例外が出て 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
| 固定リンク
「プログラミング」カテゴリの記事
- 【.NET / Win8.1 ストアアプリ】 HttpClient で TLS 1.1 / 1.2 に対応するには(2018.06.17)
- 【VS2017 15.7pv2】 XAML のランタイム ツールに 「ヒートマップ」 が増えた(2018.03.28)
- 【.NET Core】 プロジェクトを作ると 「project.assets.json が見つかりません」 エラー(2018.02.10)
- 【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)(2017.08.23)
- 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る(2017.08.16)
「-プログラミング ( わんくま )」カテゴリの記事
- [わんくま名古屋] 第21回: Metro サンプルコード解説 (1/3)(2012.04.15)
- [わんくま名古屋] 第21回は 4月 14日 - Windows 8 Metro をやるよ~♪(2012.04.12)
- [わんくま東京] 第59回の資料を公開しました(2011.06.02)
- [わんくま東京] 第59回は 5月 28日 - 名古屋から侵略します♪(2011.05.23)
- [わんくま名古屋] 第17回は 4月 9日 - TDD ネタで喋ります(2011.04.03)
この記事へのコメントは終了しました。
コメント