Я использую VS2008, предназначающийся для.NET 2.0 Платформы, и, на всякий случай, нет я не могу изменить это :)
У меня есть a DateCalculator
класс. Его метод GetNextExpirationDate
попытки определить следующее истечение, внутренне с помощью DateTime.Today
как базовая дата.
Поскольку я писал модульные тесты, я понял, что хотел протестировать GetNextExpirationDate
для различного 'сегодня' даты.
Что лучший способ состоит в том, чтобы сделать это? Вот некоторые альтернативы, которые я рассмотрел:
baselineDate
и только используйте его от модульного теста. В фактическом клиентском коде игнорируйте свойство/перегруженный метод в пользу метода, это принимает значение по умолчанию baselineDate
кому: DateTime.Today
. Я отказываюсь сделать это, поскольку это делает открытый интерфейс класса DateCalculator неловким.baselineDate
это внутренне установлено на DateTime.Today
. При тестировании получите a DateCalculatorForTesting
от DateCalculator
и набор baslineDate
через конструктора. Это содержит открытый интерфейс в чистоте, но все еще не является большим - baselineDate
был сделан защищенным, и производный класс требуется, оба только для тестирования.ExtensionAttribute
, затем реализованный это не работало бы, потому что дополнительные методы не могут получить доступ к частным/защищенным переменным. Я первоначально думал, что это было действительно вполне изящным решением.:(Я интересовался бы слушанием, какие другие думают.
Я обычно собираю вызовы к ОС внутри абстракции/интерфейса, так что я могу легко протестировать его. Так же, как и Эндрю, упомянутый выше.
Однако, учитывая только необходимость, упомянутую в вопросе; я чувствую, что 'Subclass and Override' - это самый простой и наименее инвазивный способ сделать это - вариант 2, который упомянул ОП.
public class DateCalculator
{
public DateTime GetNextExpirationDate() { // call to GetBaseLineDate() to determine result }
virtual protected GetBaseLineDate() { return DateTime.Today; }
}
// in your test assembly
public class DateCalcWithSettableBaseLine : DateCalculator
{
public DateTime BaseLine { get; set;}
override protected GetBaseLineDate()
{ return this.BaseLine; }
}
Один из вариантов - создать внутреннюю перегрузку, принимающую DateTime, и делегировать ей реальную реализацию:
public DateTime GetNextExpirationDate()
{
return GetNextExpirationDate(DateTime.Today);
}
internal DateTime GetNextExpirationDate(DateTime after)
{
// implementation goes here
}
Затем вы можете использовать InternalsVisibleToAttribute, чтобы сделать перегрузку видимой для вашей тестовой сборки, и ваша тестовая сборка сможет вызывать ее со значениями DateTime по своему усмотрению.
Вы можете использовать интерфейс, который предоставляет базовую дату. Обычно вы используете реализацию, которая возвращает DateTime.Today, но для целей тестирования можно использовать интерфейс, который позволяет вашим модульным тестам предоставлять дату.
Это также может быть полезно, если возникнет необходимость использовать текущую дату на сервере базы данных или другой машине, которая не обязательно находится там, где выполняется ваш код.
На самом деле, вот тот же вопрос с более подробными ответами, чем у меня: Unit Testing: DateTime.Now
Вы можете изменить время суток в операционной системе на компьютере, на котором выполняется тестирование. Это просто и прозрачно, но будьте осторожны с проблемами с временными метками файлов.