Другие ответы уже показали, как вы можете смоделировать цепочку свойств, чтобы обойти вашу проблему.
Но реальная проблема здесь в том, что модульное тестирование и имитация не очень хорошо работают, если вы нарушаете закон Деметры .Если вы хотите, чтобы ваш код был тестируемым и максимально пригодным для повторного использования, то вам нужно напрямую внедрить реальные зависимости вашего кода и скрыть эти зависимости за абстракциями.
Например, вместо того, чтобы делать это:
public class MyClass
{
public ControllerContext Context { get; set; }
public void DoSomething()
{
// BAD: we're only interested in the name, but instead we've injected
// a ControllerContext that can give us a HttpContext that can give us
// a User that can give us an Identity that can give us the Name.
string name = Context.HttpContext.User.Identity.Name;
// etcetera
}
}
Сделайте это:
public class MyClass
{
public INameProvider NameProvider { get; set; }
public void DoSomething()
{
// GOOD: we've injected a name provider
string name = NameProvider.Name;
// etcetera
}
}
Внедрив концепцию INameProvider
, код вашего компонента, тесты и макеты станут намного проще.Ваш код также становится более пригодным для повторного использования: он зависит только от абстрактной концепции «провайдера имен», а не от группы классов ASP.NET.Вы сможете повторно использовать свой компонент в любой среде, если возможно реализовать адаптер INameProvider
.
Компромисс заключается в том, что вам нужно будет объявить интерфейс INameProvider
и написатькласс-обёртка, который его реализует.Когда вы будете последовательно следовать этому подходу, вы получите множество небольших интерфейсов и классов адаптеров.Таков способ разработки через тестирование.
(Если вам интересно, почему я ввел INameProvider
вместо прямой установки имени - это так, чтобы контейнер IoC мог использовать интерфейс для соответствиязависимость с реализацией.)