When comparing DateTime.Now
or DateTime.UtcNow
values in tests, you've likely encountered failures due to these lines of code executing at different times, and the values therefore differing by a few milliseconds.
Technically they are different and should fail, however for testing purposes, unless absolute accuracy is required, it's useful to permit a small margin of error to account for test execution delays.
The example below will fail because now1
is defined prior to action execution, and this date will therefore be slightly earlier than the new instance of UtcNow
in the "expected" value in the assertion:
[Fact]
public async Task DatesAreEqual()
{
// Arrange
var now1 = DateTime.UtcNow;
// Act
var result = _myService.SetCreatedDate(now1);
// Assert
Assert.Equal(DateTime.UtcNow, result.CreatedDate);
}
Although in this example you're more likely to assert equality between now1
and result.CreatedDate
to make sure SetCreatedDate
is setting the date correctly, this is purely to illustrate the issue.
xUnit includes an overload for DateTime
assertions with a third parameter in the form of a TimeSpan
instance. The example below allows for a one second margin of error:
Assert.Equal(DateTime.UtcNow, result.CreatedDate, TimeSpan.FromSeconds(1));
Depending on the duration or complexity of your test, you may want to increase this margin of error to a few more seconds, or even use FromMinutes
for larger resource-intensive integration tests. If you use the same margin of error across multiple tests, it may be useful to define it as a private field:
private readonly TimeSpan _marginOfError = TimeSpan.FromSeconds(1);
Note: This overload expects a non-nullable DateTime
. If either of the comparison values are nullable, you'll need to reference it's Value
, and/or use the null forgiving operator.
Assert.Equal(now1, result.CreatedDate!.Value, _marginOfError);