У меня есть некоторые модульные тесты, которые ожидают, что «текущее время» будет отличаться от DateTime.Now, и я, очевидно, не хочу изменять время компьютера.
Какова лучшая стратегия для достижения этой цели?
У меня есть некоторые модульные тесты, которые ожидают, что «текущее время» будет отличаться от DateTime.Now, и я, очевидно, не хочу изменять время компьютера.
Какова лучшая стратегия для достижения этой цели?
DateTime
. Это будет тот, который вы тестируете, существующий метод просто вызовет перегрузкуnow
.Ответы:
Лучшая стратегия заключается в завернуть текущее время в абстракции и привнести что абстракция в потребитель .
Кроме того , вы также можете определить абстракцию времени в качестве окружающего контекста :
Это позволит вам использовать его следующим образом:
В модульном тесте вы можете заменить
TimeProvider.Current
объект Test Double / Mock. Пример использования Moq:Тем не менее, при модульном тестировании со статическим состоянием всегда не забывайте разрушать прибор , вызывая его
TimeProvider.ResetToDefault()
.источник
DateTime.UtcNow
и тому подобное, но обзоры кода в любом случае хорошая идея.Это все хорошие ответы, это то, что я сделал в другом проекте:
Использование:
Получить РЕАЛЬНУЮ дату сегодня Время
Вместо использования DateTime.Now вам нужно использовать
SystemTime.Now()
... Это не сложное изменение, но это решение может быть не идеальным для всех проектов.Путешествие во времени (Пройдет 5 лет в будущем)
Получите нашу подделку "сегодня" (через 5 лет будет "сегодня")
Сбросить дату
источник
Родинки:
Отказ от ответственности - я работаю на родинок
источник
У вас есть несколько вариантов сделать это:
Используйте фальшивый фреймворк и используйте DateTimeService (реализуйте небольшой класс-оболочку и внедрите его в производственный код). Реализация оболочки будет иметь доступ к DateTime, и в тестах вы сможете смоделировать класс оболочки.
Используйте Typemock Isolator , он может подделать DateTime.Now и не потребует от вас изменения тестируемого кода.
Используйте Moles , он также может подделать DateTime.Now и не потребует изменений в рабочем коде.
Некоторые примеры:
Класс Wrapper с использованием Moq:
Подделка DateTime напрямую с помощью Isolator:
Отказ от ответственности - я работаю в Typemock
источник
Добавьте поддельную сборку для системы (щелкните правой кнопкой мыши ссылку на систему => Добавить поддельную сборку).
И напишите в свой метод испытаний:
источник
Что касается ответа @crabcrusherclamcollector, существует проблема при использовании этого подхода в запросах EF (System.NotSupportedException: тип узла выражения LINQ 'Invoke' не поддерживается в LINQ to Entities). Я изменил реализацию так:
источник
Чтобы протестировать код, который зависит от
System.DateTime
,system.dll
необходимо смоделировать.Есть две основы, о которых я знаю, что делает это. Microsoft подделывает и смоки .
Microsoft подделывает визуальный ультиматум студии 2012 года и работает прямо из комптона.
Smocks является открытым исходным кодом и очень прост в использовании. Его можно скачать с помощью NuGet.
Следующее показывает макет
System.DateTime
:источник
Поток безопасного
SystemClock
использованияThreadLocal<T>
прекрасно работает для меня.ThreadLocal<T>
доступно в .Net Framework v4.0 и выше.Пример использования:
источник
Now
экземпляр.AsyncLocal
вместоThreadLocal
Console.WriteLine(SystemClock.Now); SystemClock.Set(new DateTime(2017, 01, 01)); Console.WriteLine(SystemClock.Now); await Task.Delay(1000); Console.WriteLine(SystemClock.Now);
Я столкнулся с этой же проблемой, но нашел исследовательский проект от Microsoft, который решает эту проблему.
http://research.microsoft.com/en-us/projects/moles/
Moles - это облегченная среда для тестирования заглушек и обходов в .NET, основанная на делегатах. Кроты могут использоваться для обхода любого метода .NET, включая не виртуальные / статические методы в закрытых типах.
Пример кода был изменен с оригинала.
Я сделал то, что другие предложили и абстрагировал DateTime в поставщика. Это было просто неправильно, и я чувствовал, что это слишком много только для тестирования. Я собираюсь реализовать это в моем личном проекте этим вечером.
источник
Одна особая заметка о насмешках
DateTime.Now
с поводу TypeMock ...Значение
DateTime.Now
должно быть помещено в переменную, чтобы это было правильно смоделировано. Например:Это не работает:
Тем не менее, это делает:
источник
Макет объектов.
Поддельный DateTime, который возвращает Now, подходящий для вашего теста.
источник
Я удивлен, что никто не предложил один из самых очевидных путей:
Тогда вы можете просто переопределить этот метод в вашем двойном тесте.
Мне также нравится вводить
TimeProvider
класс в некоторых случаях, но для других этого более чем достаточно. Я, вероятно, предпочел быTimeProvider
версию, если вам нужно использовать это в нескольких классах, хотя.РЕДАКТИРОВАТЬ: Для всех, кто заинтересован, это называется добавлением «шва» в ваш класс, точки, где вы можете подключиться к его поведению, чтобы изменить его (для целей тестирования или иным образом) без необходимости фактически изменять код в классе.
источник
Хорошая практика, когда DateTimeProvider реализует IDisposable.
Далее вы можете ввести свой фальшивый DateTime для модульных тестов
Смотрите пример Пример DateTimeProvider
источник
Чистый способ сделать это - ввести VirtualTime. Это позволяет контролировать время. Сначала установите VirtualTime
Это позволяет, например, увеличивать время, которое перемещается в 5 раз при всех вызовах DateTime.Now или UtcNow.
Чтобы замедлить время, например, в 5 раз
Чтобы время остановилось
Движение назад во времени еще не проверено
Вот пример теста:
Вы можете проверить больше тестов здесь:
https://github.com/VirtualTime/VirtualTime/blob/master/VirtualTimeLib.Tests/when_virtual_time_is_used.cs
То, что дает вам расширение DateTime.Now.ToVirtualTime, является экземпляром ITime, который вы передаете методу / классу, который зависит от ITime. Некоторые DateTime.Now.ToVirtualTime настраиваются в контейнере DI на ваш выбор
Вот еще один пример внедрения в классовое устройство
источник
Мы использовали статический объект SystemTime, но столкнулись с проблемами при выполнении параллельных модульных тестов. Я попытался использовать решение Хенка Ван Бойджена, но у меня возникли проблемы в порожденных асинхронных потоках, и в итоге я использовал AsyncLocal, как показано ниже:
Источник: https://gist.github.com/CraftyFella/42f459f7687b0b8b268fc311e6b4af08
источник
Старый вопрос, но все еще в силе.
Мой подход заключается в создании нового интерфейса и класса для переноса
System.DateTime.Now
вызоваЭтот интерфейс может быть вставлен в любой класс, который должен получить текущую дату и время. В этом примере у меня есть класс, который добавляет временной интервал к текущей дате и времени (тестируемый модуль System.DateTime.Now.Add (TimeSpan))
И тесты могут быть написаны, чтобы убедиться, что он работает правильно. Я использую NUnit и Moq, но любой тестовый фреймворк подойдет
Этот шаблон будет работать для любых функций, которые зависят от внешних факторов, таких как
System.Random.Next()
,System.DateTime.Now.UtcNow
иSystem.Guid.NewGuid()
т. Д.См. Https://loadlimited.visualstudio.com/Stamina/_git/Stamina.Core для получения дополнительных примеров или получения пакета nuget https://www.nuget.org/packages/Stamina.Core .
источник
Вы можете изменить класс, который вы тестируете, на использование класса,
Func<DateTime>
который будет передаваться через его параметры конструктора, поэтому, когда вы создаете экземпляр класса в реальном коде, вы можете передать() => DateTime.UtcNow
егоFunc<DateTime>
параметру, а в тесте вы можете пройти время хочу проверить.Например:
источник
У меня та же проблема, но я думал, что мы не должны использовать установленные даты и времени в одном классе. потому что это может привести к неправильному использованию в один прекрасный день. поэтому я использовал провайдера, как
Для тестов в тестовом проекте сделан помощник, который будет заниматься заданными вещами,
по коду
и на тестах
Но нужно помнить одну вещь, иногда реальное DateTime и DateTime провайдера не действуют одинаково
Я предположил, что задержка будет максимальной TimeSpan.FromMilliseconds (0.00002) . Но в большинстве случаев это еще меньше
Найти образец в MockSamples
источник
Вот мой ответ на этот вопрос. Я комбинирую шаблон «Ambient Context» с IDisposable. Таким образом, вы можете использовать DateTimeProvider.Current в обычном программном коде, а в тесте вы переопределяете область с помощью оператора using.
Вот как использовать вышеупомянутый DateTimeProvider внутри юнит-теста
источник
Используя его,
ITimeProvider
мы были вынуждены перенести его в специальный общий общий проект, на который должны ссылаться остальные остальные проекты. Но это усложняло контроль зависимостей .Мы искали
ITimeProvider
в .NET Framework. Мы искали пакет NuGet и нашли тот, с которым нельзя работатьDateTimeOffset
.Поэтому мы придумали собственное решение, которое зависит только от типов стандартной библиотеки. Мы используем экземпляр
Func<DateTimeOffset>
.Как пользоваться
Как зарегистрироваться
Autofac
( Для будущих редакторов: добавьте свои случаи здесь ).
Как провести юнит-тест
источник
Может быть, менее профессиональный, но более простое решение может быть сделать параметр DateTime в потребительском методе. Например, вместо метода make, такого как SampleMethod, сделать SampleMethod1 с параметром. Тестирование SampleMethod1 проще
источник