-
Notifications
You must be signed in to change notification settings - Fork 732
Method to assert the millisecond part of a DateTime / DateTimeOffset instance #2738
Description
Background and motivation
Currently, FluentAssertions has methods to assert the year, month, day, hour, minute, second and offset of a DateTimeOffset (HaveX), but an equivalent method for the millisecond part is missing. Generally, it would be nice to assert the millisecond part in the style of FluentAssertions instead of using result.Millisecond.Should().Be(milliseconds).
I'm currently working on a library that provides convenience methods based on DateTime/DateTimeOffset and implement date and time related unit tests for it.
This is very easy to implement, because we can extend the DateTimeAssertions class and DateTimeOffsetAssertions class by a method called HaveMillisecond.
The implementation of this method could look like following:
public AndConstraint<DateTimeOffsetAssertions> HaveMillisecond(int expectedMilliseconds, string because = "", params object[] becauseArgs)
{
Execute.Assertion
.ForCondition(this.Subject != null)
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:DateTimeOffset} to have milliseconds {0}{reason}, but found <null>.", expectedMilliseconds);
Execute.Assertion
.ForCondition(this.Subject!.Value.Millisecond == expectedMilliseconds)
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:DateTimeOffset} to have milliseconds {0}{reason}, but found {1}.", expectedMilliseconds, this.Subject.Value.Millisecond);
return new AndConstraint<DateTimeOffsetAssertions>(this);
}Also the opponent of HaveMillisecond, which would be NotHaveMillisecond, can be implemented this way by inverting / changing the condition to this.Subject!.Value.Millisecond != expectedMilliseconds.
API Proposal
public class DateTimeOffsetAssertions<TAssertions>
{
public AndConstraint<DateTimeOffsetAssertions> HaveMillisecond(int expectedMilliseconds, string because = "", params object[] becauseArgs);
public AndConstraint<DateTimeOffsetAssertions> NotHaveMillisecond(int expectedMilliseconds, string because = "", params object[] becauseArgs);
}public class DateTimeAssertions<TAssertions>
{
public AndConstraint<DateTimeAssertions> HaveMillisecond(int expectedMilliseconds, string because = "", params object[] becauseArgs);
public AndConstraint<DateTimeAssertions> NotHaveMillisecond(int expectedMilliseconds, string because = "", params object[] becauseArgs);
}API Usage
var dateTimeOffset = DateTimeOffset.Parse("2024-08-23T00:00:00.123+00:00");
dateTimeOffset.Should().HaveMilliseconds(123);
dateTimeOffset.Should().NotHaveMilliseconds(124);Alternative Designs
Alternately, you could write an extension method based on DateTimeOffsetAssertions class and add there the HaveMillisecond method. This would not directly change the API of FluentAssertions, but would not be consistent with the rest of the DateTime/DateTimeOffset method provided by FluentAssertions.
The extension method could be implemented like following:
internal static class DateTimeOffsetAssertionsExtensions
{
internal static FluentAssertions.Primitives.DateTimeOffsetAssertions HaveMillisecond(
this FluentAssertions.Primitives.DateTimeOffsetAssertions assertions,
int expectedMilliseconds,
string because = "",
params object[] becauseArgs)
{
var subject = assertions.Subject;
Execute.Assertion
.ForCondition(subject != null)
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:DateTimeOffset} to have milliseconds {0}{reason}, but found <null>.", expectedMilliseconds);
Execute.Assertion
.ForCondition(subject!.Value.Millisecond == expectedMilliseconds)
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:DateTimeOffset} to have milliseconds {0}{reason}, but found {1}.", expectedMilliseconds, subject.Value.Millisecond);
return assertions;
}
}Risks
None, because it adds an extra method to assert the millisecond part of a DateTime / DateTimeOffset instance.
Are you willing to help with a proof-of-concept (as PR in that or a separate repo) first and as pull-request later on?
Yes, please assign this issue to me.