Свободные утверждения: Использование BeCloseTo в коллекции свойств DateTime

Я обрабатываю несколько элементов, каждый из которых содержит свойство DateProcessed (обнуляемый DateTime) и хочу утверждать, что это свойство установлено на текущую дату. К тому времени, когда он проходит через процедуру обработки, все даты немного различаются.

Я хочу проверить, что все свойства DateProcessed имеют относительный (100 мс) недавний DateTime.

Fluent Assertions имеет метод.BeCloseTo, который отлично работает для одного элемента. Но я хочу использовать это для всей коллекции. Но это не доступно через Contains() при просмотре коллекции.

Упрощенный пример...

[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? :(
    }

}

3 ответа

Решение

Как прямой ответ на ваш вопрос, вы можете сделать что-то вроде items.Should().OnlyContain(i => (i - DateTime.Now) < TimeSpan.FromMilliseconds(100)),

Тем не менее, модульный тест, который опирается на DateTime.Now это очень плохая практика. Что вы можете сделать, это представить что-то вроде этого:

public static class SystemContext
{
    [ThreadStatic]
    private static Func<DateTime> now;

    public static Func<DateTime> Now
    {
        get { return now ?? (now = () => DateTime.Now); }
        set { now = value; }
    }
}

Тогда вместо того, чтобы ссылаться на DateTime.Nowиспользовать SystemContext.Now() чтобы узнать текущее время. Если вы сделаете это, вы можете "установить" текущее время для конкретного модульного теста, например:

SystemContext.Now = () => 31.March(2013).At(7, 0);

Вы можете сделать это в 3.5, настроив параметры ShouldBeEquivalentTo, Например:

result.ShouldBeEquivalentTo(expected, options =>
{
    options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>();
    return options;
});

или кратко:

result.ShouldBeEquivalentTo(expected, options => options.Using<DateTimeOffset>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTimeOffset>());

Если вы хотите настроить это глобально, внедрите следующее в методе установки фикстур вашей инфраструктуры тестирования:

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;
});

Я только что решил это так...

[Test]
public void then_all_items_must_be_set_to_the_current_time()
{
    items.Should().OnlyContain(x => DateTime.Now.Subtract(x.Value).Milliseconds <= 100);
}

Но если кто-нибудь знает о способах "Свободных подтверждений", как это делается, пожалуйста, дайте мне знать.

Другие вопросы по тегам