Mocking System.Web.TraceContext с Moq - PullRequest
0 голосов
/ 26 июля 2011

У меня есть некоторый код, который обращается к объекту HttpContextBase.Trace и делает с ним некоторые вещи (проверка IsEnabled, написание некоторых сообщений).Проблема в том, что это System.Web.TraceContext объект.TraceContext - это запечатанный класс с одним конструктором: он принимает объект HttpContext.Мок не может издеваться над TraceContext или HttpContext.Могу ли я сделать что-нибудь здесь, чтобы проверить этот код с Moq?

Или мне нужно будет выделить этот код и перестать ссылаться на HttpContextBase.Trace?

1 Ответ

1 голос
/ 27 июля 2011

Я как бы ненавижу ответы, которые говорят «не делай этого», потому что в ответе может быть ценность, независимо от подхода, однако здесь мы идем:

Не делай этого.

Предположим, у вас есть этот класс:

public class MyCode
{
    public void Do()
    {
        HttpContext.Current.Trace.WriteLine("WOO!");
    }
}

Такие вещи не очень проверяемы.Если вы хотите провести рефакторинг для тестируемости, вы можете использовать метод типа «инверсия управления».Здесь я буду использовать «внедрение зависимостей» (есть и другие варианты, такие как «расположение службы» и «абстрактные фабрики», но это легче понять):

public class MyCode
{
    private IMyLogger _logger = null;
    public MyCode(IMyLogger logger)
    {
        _logger = logger;
    }

    public void Do()
    {
        _logger.TraceWriteLine("WOO!");
    }
}

Теперь вы можете видеть, что этот кодочень тестируем, и вам не нужно перепрыгивать через обручи, чтобы что-то высмеивать.

//Confirms "Do" method calls "TraceWriteLine"
public void Do_Called_CallsTraceWriteLine()
{
    //Arrange
    var loggerMock = new Mock<IMyLogger>();
    loggerMock.Setup(l => l.TraceWriteLine(It.IsAny<string.());

    var target = new MyCode(loggerMock.Object);

    //Act
    target.Do();

    //Assert
    loggerMock.VerifyAll(); 
}

Теперь ваша реализация IMyLogger может вызывать HttpContext, но она поддерживает ваш целевой класс тестируемым.

public DefaultLogger : IMyLogger
{
    public void TraceWriteLine(string message)
    {
        HttpContext.Current.Trace.WriteLine(message);
    }
}

Чтобы реализовать такую ​​вещь, многие люди предпочитают использовать Inversion of Control контейнер .Вам не нужно этого делать, но это делает вещи немного проще и не снижает удобство обслуживания, поскольку вы добавляете больше зависимостей.Вы можете вообразить, что если бы у вас был интерфейс для каждой части .NET Framework, который был непроверенным, ваши вызовы конструктора «new MyCode» начали бы становиться довольно длинными.Контейнеры IoC помогут вам избежать этого.

Популярные контейнеры IoC для .NET:

  • Ninject
  • Unity
  • MEF (встроенный в .NET 4.0)
  • Autofac
  • Castle Windsor
  • StructureMap

Ваш пост помечен как "ASP.NET".Надеюсь, вы используете MVC.Если это так, он имеет новую поддержку для внедрения зависимостей, примеры здесь: http://weblogs.asp.net/shijuvarghese/archive/2011/01/21/dependency-injection-in-asp-net-mvc-3-using-dependencyresolver-and-controlleractivator.aspx

Надеюсь, это поможет.Извините, это не дает прямого ответа на ваш вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...