Только представьте, что мой метод контроллера asp.net mvc может иметь такой код:
testplanService.AddTestplan(testplan,template,release);
Я не хочу ничего такого представлять.Правильный путь заключается в том, что ваш контроллер работает с абстракциями, а не с реальными реализациями.Поэтому вместо того, чтобы зависеть от фактической реализации службы, эта переменная testplanService
, которую вы используете в своем контроллере, будет простым интерфейсом или абстрактным классом, который будет введен в конструктор вашего контроллера.
Теперь в своем модульном тесте вы можете фактически смоделировать этот интерфейс и протестировать свой контроллер в отдельности.
Теперь давайте рассмотрим фактическую реализацию службы:
public void AddTestplan(Testplan testplan, Template template, Release release)
{
testplan.CreatedAt = DateTime.Now;
testplan.UserId = WindowsIdentity.GetCurrent().Name;
testplan.Name = release.Name + " " + template.Name + " " + testplan.UserId + " " + testplan.CreatedAt;
_provider.AddTestplan(testplan, template, release);
}
ТамЕсть пара проблем с этим методом.Прежде всего, это зависит от недетерминированных данных, таких как DateTime.Now
, которые трудно провести модульное тестирование.У Мартина Фаулера есть хорошая статья о недетерминизме в модульных тестах.Это также зависит от текущего WindowsIdentity
.Все это сложно для модульного тестирования, потому что ваш метод зависит от реальных реализаций, а не от работы с абстракциями.
Таким образом, вам придется абстрагироваться от тех понятий, стоящих за провайдерами, которые вы можете использовать в своем модульном тесте.Убедитесь, что все ваши компоненты слабо связаны между собой.Вам будет гораздо проще работать с ними изолированно.
ОБНОВЛЕНИЕ:
Как указано в разделе комментариев, здесь приведен пример того, как абстрагировать поиск по дате и времени:
Рассмотрим следующий класс:
public class WeekendTester
{
public bool IsWeekendSoon()
{
return (int)DateTime.Now.DayOfWeek > 3;
}
}
Очевидно, что модульное тестирование IsWeekendSoon
очень сложно, так как оно будет зависеть от дня, когда выполняется ваш модульный тест.
Таким образом, чтобы устранить недетерминизм в этом методе, вы можете сделать следующее:
public class WeekendTester
{
private readonly Func<DateTime> _dateTimeProvider;
public WeekendTester(Func<DateTime> dateTimeProvider)
{
_dateTimeProvider = dateTimeProvider;
}
public bool IsWeekendSoon()
{
return (int)_dateTimeProvider().DayOfWeek > 3;
}
}
Теперь все, что вам нужно, - это настроить вашу любимую инфраструктуру DI для внедрения () => DateTime.Now
в конструктор этого объекта и внутри вашего модульного теста вы можете легко смоделировать его:
[TestMethod]
public void Weekend_Is_Still_Far_Away_From_The_28_th_Of_February_2012()
{
// arrange
Func<DateTime> providerMock = () => new DateTime(2012, 2, 28);
var sut = new WeekendTester(providerMock);
// act
var actual = sut.IsWeekendSoon();
// assert
Assert.IsFalse(actual);
}
Вы можете увидеть, как в этом примере мы можем заставить метод работать с любой датоймы хотим, чтобы это было в модульном тесте, чтобы проверить правильность поведения метода.