C# と Database ではそれぞれミリ秒の保持の仕方が異なります。上手く Assert するには比較用のクラスを作って、 Assert の Parameter に渡してあげれば OK です。
使っているもの
- xUnit
- SQL Server
なぜ起きるのか
C# の DateTime ではミリ秒を正しく保持しています。
C#: 2013-05-01 23:59:59.991
しかし、これを SQL Server の datetime に入れるとこうなります。
SQL Server: 2013-05-01 23:59:59.990
これには理由があって、ミリ秒の精度が .000、.003、.007 であるためです。よって、このまま Assert.Equals すると Fail してしまいます。
解決方法
比較用のクラスをパラメーターで渡してあげて、多少の時間を許容するようにします。
Assert.Equal(expected, actual, new SqlServerDateTimeComparer());
比較用のクラス
いくつか用意してあるので合ったものを使ってください。また、このクラスでは 10 秒までの差は許容しているので、この設定値は Constructor で受け取れるようにするなどすれば、別の比較 (e.g. DateTime が DI 出来なくて死ぬ Unit Test など) にも使えると思います。
public class SqlServerNullableDateTimeComparer : IEqualityComparer<DateTime?>
{
public bool Equals(DateTime? x, DateTime? y)
{
if (x == null && y == null)
{
return true;
}
if (x == null || y == null)
{
return false;
}
return (x.Value - y.Value).Duration() < TimeSpan.FromSeconds(10);
}
public int GetHashCode(DateTime? obj)
{
return obj.GetHashCode();
}
}
public class SqlServerDateTimeComparer : IEqualityComparer<DateTime>
{
public bool Equals(DateTime x, DateTime y)
{
return (x - y).Duration() < TimeSpan.FromSeconds(10);
}
public int GetHashCode(DateTime obj)
{
return obj.GetHashCode();
}
}
public class SqlServerNullableDateTimeOffsetComparer : IEqualityComparer<DateTimeOffset?>
{
public bool Equals(DateTimeOffset? x, DateTimeOffset? y)
{
if (x == null && y == null)
{
return true;
}
if (x == null || y == null)
{
return false;
}
return (x.Value - y.Value).Duration() < TimeSpan.FromSeconds(10);
}
public int GetHashCode(DateTimeOffset? obj)
{
return obj.GetHashCode();
}
}
public class SqlServerDateTimeOffsetComparer : IEqualityComparer<DateTimeOffset>
{
public bool Equals(DateTimeOffset x, DateTimeOffset y)
{
return (x - y).Duration() < TimeSpan.FromSeconds(10);
}
public int GetHashCode(DateTimeOffset obj)
{
return obj.GetHashCode();
}
}
Note
DATETIME データ型のミリ秒に関する注意事項 – Microsoft SQL Server Japan Support Team Blog