У меня есть некоторые модульные тесты, который ожидает, что 'текущее время' будет отличаться, чем DateTime. Теперь и я не хочу изменять время компьютера, очевидно.
Что лучшая стратегия состоит в том, чтобы достигнуть этого?
Лучшая стратегия - заключить текущее время в абстракцию и внедрить эту абстракцию в потребителя .
В качестве альтернативы вы также можете определить абстракцию времени как Внешний контекст :
public abstract class TimeProvider
{
private static TimeProvider current =
DefaultTimeProvider.Instance;
public static TimeProvider Current
{
get { return TimeProvider.current; }
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
TimeProvider.current = value;
}
}
public abstract DateTime UtcNow { get; }
public static void ResetToDefault()
{
TimeProvider.current = DefaultTimeProvider.Instance;
}
}
Это позволит вам использовать его следующим образом:
var now = TimeProvider.Current.UtcNow;
В модульном тесте вы можете заменить TimeProvider.Current
с объектом Test Double / Mock. Пример использования Moq:
var timeMock = new Mock<TimeProvider>();
timeMock.SetupGet(tp => tp.UtcNow).Returns(new DateTime(2010, 3, 11));
TimeProvider.Current = timeMock.Object;
Однако при модульном тестировании со статическим состоянием всегда не забывайте разрушить ваше устройство , вызвав TimeProvider.ResetToDefault ()
.
У вас есть несколько вариантов для этого:
Используйте фиктивный фреймворк и используйте DateTimeService (реализуйте небольшой класс-оболочку и вставьте его в производственный код). Реализация оболочки будет обращаться к DateTime, и в тестах вы сможете имитировать класс оболочки.
Используйте Typemock Isolator , он может подделать DateTime.Now и не потребует от вас изменения тестируемого кода.
Используйте Moles , он также может подделывать DateTime.Now и не требует изменения производственного кода.
Некоторые примеры:
Класс-оболочка с использованием Moq:
[Test]
public void TestOfDateTime()
{
var mock = new Mock<IDateTime>();
mock.Setup(fake => fake.Now)
.Returns(new DateTime(2000, 1, 1));
var result = new UnderTest(mock.Object).CalculateSomethingBasedOnDate();
}
public class DateTimeWrapper : IDateTime
{
public DateTime Now { get { return DateTime.Now; } }
}
Подделка DateTime напрямую с помощью Isolator:
[Test]
public void TestOfDateTime()
{
Isolate.WhenCalled(() => DateTime.Now).WillReturn(new DateTime(2000, 1, 1));
var result = new UnderTest().CalculateSomethingBasedOnDate();
}
Заявление об ограничении ответственности - я работаю в Typemock
Поддельные объекты.
Макет DateTime, который возвращает Now, подходящий для вашего теста.
Родинки:
[Test]
public void TestOfDateTime()
{
var firstValue = DateTime.Now;
MDateTime.NowGet = () => new DateTime(2000,1,1);
var secondValue = DateTime.Now;
Assert(firstValue > secondValue); // would be false if 'moleing' failed
}
Заявление об ограничении ответственности - я работаю над Родинками