I'm processing a number of items, each of which contain a DateProcessed property (a nullable DateTime) and want to Assert that the property is set to the current date. By the time it gets through the processing routine the dates are all slightly different.
I want to Test that all the DateProcessed properties have a relativity (100ms) recent DateTime.
Fluent Assertions has the .BeCloseTo method which works perfectly for a single item. But I want to use that for the entire collection. But it's not available via the Contains() when looking at a collection.
A simplified example ...
[TestFixture]
public class when_I_process_the_items
{
[SetUp]
public void context()
{
items = new List<DateTime?>(new [] { (DateTime?)DateTime.Now, DateTime.Now, DateTime.Now } );
}
public List<DateTime?> items;
[Test]
public void then_first_item_must_be_set_to_the_current_time()
{
items.First().Should().BeCloseTo(DateTime.Now, precision: 100);
}
[Test]
public void then_all_items_must_be_set_to_the_current_time()
{
items.Should().Contain .... //Not sure? :(
}
}
You can do this in 3.5 by configuring the options to ShouldBeEquivalentTo
. For example:
result.ShouldBeEquivalentTo(expected, options =>
{
options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>();
return options;
});
or succintly:
result.ShouldBeEquivalentTo(expected, options => options.Using<DateTimeOffset>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTimeOffset>());
If you want to set this up globally, implement the following in your testing framework's fixture setup method:
AssertionOptions.AssertEquivalencyUsing(options =>
{
options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>();
options.Using<DateTimeOffset>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTimeOffset>();
return options;
});
As a direct answer to your question, you can do something like items.Should().OnlyContain(i => (i - DateTime.Now) < TimeSpan.FromMilliseconds(100))
.
However, a unit test that relies on DateTime.Now
is a very bad practice. What you can do is to introduce something like this:
public static class SystemContext
{
[ThreadStatic]
private static Func<DateTime> now;
public static Func<DateTime> Now
{
get { return now ?? (now = () => DateTime.Now); }
set { now = value; }
}
}
Then instead of referring to DateTime.Now
, use SystemContext.Now()
to get the current time. If you do that, you can 'set' the current time for a particular unit test like this:
SystemContext.Now = () => 31.March(2013).At(7, 0);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With