通常の解決策は、インターフェイスの背後にそれを隠すことです。 ユニットテストでDateTime.Nowを模擬する方法は?
public class RecordService
{
private readonly ISystemTime systemTime;
public RecordService(ISystemTime systemTime)
{
this.systemTime = systemTime;
}
public void RouteRecord(Record record)
{
if (record.Created <
systemTime.CurrentTime().AddMonths(-2))
{
// process old record
}
// process the record
}
}
ユニットテストでは、モックオブジェクトを使用し、私は現在の時刻を得るために、私のクラスに別のインターフェイスを注入するために好きではない
[TestClass]
public class When_old_record_is_processed
{
[TestMethod]
public void Then_it_is_moved_into_old_records_folder()
{
var systemTime = A.Fake<ISystemTime>();
A.CallTo(() => system.Time.CurrentTime())
.Returns(DateTime.Now.AddYears(-1));
var record = new Record(DateTime.Now);
var service = new RecordService(systemTime);
service.RouteRecord(record);
// Asserts...
}
}
を返すように決めることができます。このような小さな問題のために重すぎる解決策を感じています。解決策は、public関数で静的クラスを使用することです。
public static class SystemTime
{
public static Func<DateTime> Now =() => DateTime.Now;
}
今、私たちはISystemTime注射を削除することができますし、RecordServiceは、我々は同じように簡単にシステム時刻を模擬することができますユニットテストでこの
public class RecordService
{
public void RouteRecord(Record record)
{
if (record.Created < SystemTime.Now.AddMonths(-2))
{
// process old record
}
// process the record
}
}
のように見えます。もちろん
[TestClass]
public class When_old_record_is_processed
{
[TestMethod]
public void Then_it_is_moved_into_old_records_folder()
{
SystemTime.Now =() => DateTime.Now.AddYears(-1);
var record = new Record(DateTime.Now);
var service = new RecordService();
service.RouteRecord(record);
// Asserts...
}
}
このすべての欠点があります。パブリックフィールド(HORROR!)を使用しているので、誰もこのようなコードを書くことを止めていません。
public class RecordService
{
public void RouteRecord(Record record)
{
SystemTime.Now =() => DateTime.Now.AddYears(10);
}
}
また、開発者を教育するのは、間違いを犯さないように抽象化を作成するよりも優れていると思います。他の可能性のある問題は、テストの実行に関連しています。この機能を元の状態に戻すことを忘れた場合、他のテストに影響する可能性があります。これは単体テストランナがテストを実行する方法によって異なります。 あなたは、公共の機能を使用して(時間、単純なファイルシステム操作をあざける)この種の機能を実装する私の意見ではモックのファイルシステム操作に
public static class FileSystem
{
public static Action<string, string> MoveFile = File.Move;
}
を同じロジックを使用することができます完全に受け入れています。コードを読みやすくし、依存関係を減らし、単体テストを模擬するのは簡単です。
moqを使用しましたか? (またはその他の模擬フレームワーク)http://code.google.com/p/moq/ – Magrangs
コードの定式化を修正しました。それを正しく行う方法については、あなたのバージョンと比較してください。 –
@Magrangs:Moqは、他のすべての「正常な」モッキングフレームワークと同様に、静的メソッドやプロパティを模倣することはできません。「DateTime.Now」。 –