Подтвердить что ты не робот

Моческое статическое свойство с moq

Я новичок в использовании moq. Я создаю некоторый случай unit test для HttpModule, и все работает нормально, пока я не удалю свойство static следующим образом

this.applicationPath = (HttpRuntime.AppDomainAppVirtualPath.Length > 1) ? HttpRuntime.AppDomainAppVirtualPath : String.Empty;

Я не знаю, как создать mocks для класса static и свойства типа HttpRuntime.AppDomainAppVirtualPath. context, request и response были издевались над образцом кода, который я получаю от moq. Я буду признателен, если кто-нибудь сможет мне помочь в этом.

4b9b3361

Ответ 1

Moq не может подделывать статические элементы.

В качестве решения вы можете создать класс-оболочку (шаблон адаптера), содержащий статическое свойство и подделать его элементы.
Например:

public class HttpRuntimeWrapper
{
    public virtual string AppDomainAppVirtualPath 
    { 
        get
        { 
            return HttpRuntime.AppDomainAppVirtualPath; 
        }
    }
}

В производственном коде вы можете получить доступ к этому классу вместо HttpRuntime и подделать это свойство:

[Test]
public void AppDomainAppVirtualPathTest()
{
    var mock = new Moq.Mock<HttpRuntimeWrapper>();
    mock.Setup(fake => fake.AppDomainAppVirtualPath).Returns("FakedPath");

    Assert.AreEqual("FakedPath", mock.Object.AppDomainAppVirtualPath);
}

Другим решением является использование изолирующей структуры (как Typemock Isolator), в которой вы можете подделывать статические классы и члены.
Например:

Isolate.WhenCalled(() => HttpRuntime.AppDomainAppVirtualPath)
       .WillReturn("FakedPath");

Отказ от ответственности - я работаю на Typemock

Ответ 2

Вы не можете статические методы Moq с Moq.

В действительности это не так, статические методы и классы имеют свое место, но для логики они затрудняют модульное тестирование. Естественно, вы столкнетесь с ними при использовании других библиотек. Чтобы обойти это, вам нужно будет написать adapter (обертку) вокруг статического кода и предоставить интерфейс. Например:

// Your static class - hard to mock
class StaticClass
{
   public static int ReturnOne() 
   {
       return 1;
   }
}

// Interface that you'll use for a wrapper
interface IStatic
{
    int ReturnOne();
}

Примечание. Я пропустил конкретный класс, который использует IStatic для производственного кода. Все это будет класс, который использует IStatic, и ваш производственный код будет использовать этот класс, а не StaticClass выше.

Тогда с Moq:

var staticMock = new Mock<IStatic>();
staticMock.Setup(s => s.ReturnOne()).Returns(2);

Ответ 3

Как уже упоминалось в предыдущих ответах, вы не можете использовать MoQ для статических методов, и если вам нужно, ваш лучший снимок - создать оболочку вокруг статического класса.

Однако недавно я обнаружил Moles project. С домашней страницы; "Moles позволяет заменить любой .NET-метод делегатом. Moles поддерживает статические или не виртуальные методы". Это может быть полезно для вашей текущей ситуации.

Ответ 4

Лучшее решение, которое я нашел до сих пор, это Telerik JustMock - к сожалению, только платная версия позволяет издеваться над статикой.

Хотя идея обертывания статики - хорошая, вы не всегда можете это сделать. Если вы хотите протестировать некоторый код, который уже использует некоторые статические классы, тогда не всегда можно отключить и использовать обертку. В этом случае JustMock выглядит разумным решением, и я, вероятно, собираюсь использовать его на некоторых решениях в ближайшем будущем.

Ответ 6

Использование Microsoft Fakes, как предлагает @Sujith, является жизнеспособным решением. Вот как вы на самом деле это делаете:

  • Найдите System.Web в вашей ссылке на ваш тестовый проект и щелкните правой кнопкой мыши
  • Выберите "Добавить". Это добавляет ссылку System.Web.4.0.0.0.Fakes
  • Используйте следующий код:

    using (Microsoft.QualityTools.Testing.Fakes.ShimsContext.Create()) {System.Web.Fakes.ShimHttpRuntime.AppDomainAppVirtualPathGet =() => "/"; //Do what ever needs the faked AppDomainAppVirtualPath }//Делать то, что когда-либо нуждается в фальшивом AppDomainAppVirtualPath}