Time travel with TimeProvider
Ak píšete unit testy viete, že používať priamo DateTime.Now
nie je dobrý nápad 🤔.
Pravdepodobne máte vo svojom projekte niečo ako IDateTimeProvider
, alebo niečo podobné.
🌠 Microsoft po 21 rokoch prišiel s vlastným riešením. Počnúc .NET 8 máme k dispozícii abstraktnú triedu TimeProvider
. Tú môžeme injektnúť tam, kde ju potrebujeme a používať ju.
V projekte potom nastavíme použitie na TimeProvider.System
.
🧪 V testoch môžeme použiť triedu FakeTimeProvider
z knižnice Microsoft.Extensions.Time.Testing
.
Táto trieda nám umožní cestovať v čase pri písaní načích testov.
Použite nový TimeProvider
namiesto pôvodného DateTime.Now
alebo DateTime.UtcNow
.
// 👇 Inject time provider
public class Basket(TimeProvider timeProvider, LoyaltyLevel loyaltyLevel)
{
private readonly DateTimeOffset _expireAt = timeProvider.GetUtcNow() // 👈 Use time provider
.AddDays(loyaltyLevel == LoyaltyLevel.Standard ? 1 : 7);
public bool IsExpired => timeProvider.GetUtcNow() > _expireAt; // 👈 Use time provider
}
TimeProvider.System
je k dispozícii pre štandardné situáci. Použite ho tam, kde ho potrebujete.
// 👇 Use System time provider in your code
var basket = new Basket(TimeProvider.System, LoyaltyLevel.Gold);
V testoch použite FakeTimeProvider
a cestujte v čase podľa potreby pomocou metódy Advance
.
[Fact]
public void GoldendUserShouldBeExpiredAfter7Days()
{
// 👇 Use fake time provider in your test
var fakeTime = new FakeTimeProvider(DateTimeOffset.UtcNow);
var basket = new Basket(fakeTime, LoyaltyLevel.Gold);
// 👇 Travel in time
fakeTime.Advance(TimeSpan.FromDays(8));
Assert.True(basket.IsExpired);
}