過去有些程式與時間相關,測試並不好做。例如以下的受測程式:
public static string Greeting() { string returnValue = "Good Evening!"; DateTimeOffset dateTimeOffset = DateTimeOffset.Now; int hour = dateTimeOffset.Hour; if (hour > 4) { if (hour > 11) { if (hour < 18) { returnValue = "Good Afternoon!"; } } else { returnValue = "Good Morning!"; } } return returnValue; }
如果我的測試是這麼寫:
string greeting = Program.Greeting(); Assert.Equal("Good Afternoon!", greeting);
很明顥地,只能在下午進行測試才會通過。其中的關鍵,就是程式中呼叫到「現在」這種與時間相關的,諸如
public static string GreetingV2(System.TimeProvider? timeProvider) { string returnValue = "Good Evening!"; System.TimeProvider _timeProvider = System.TimeProvider.System; if (timeProvider != null) { _timeProvider = timeProvider; } DateTimeOffset dateTimeOffset = _timeProvider.GetLocalNow(); int hour = dateTimeOffset.Hour; if (hour > 4) { if (hour > 11) { if (hour < 18) { returnValue = "Good Afternoon!"; } } else { returnValue = "Good Morning!"; } } return returnValue; }
同時調整測試程式的寫法:
DateTimeOffset dateTimeOffset = new(2024, 5, 15, 16, 58, 0, TimeZoneInfo.Local.BaseUtcOffset); TimeProvider fakeTimeProvider = new Microsoft.Extensions.Time.Testing.FakeTimeProvider(dateTimeOffset); string greeting = Program.GreetingV2(fakeTimeProvider); Assert.Equal("Good Afternoon!", greeting);
如此一來,不論未來何時執行測試程式,「現在」都固定在設計下的時間點,而且受影響的原程式範圍也縮限到非常小,還算不錯吧?