Моческое статическое свойство с moq
Я новичок в использовании moq. Я создаю некоторый случай unit test для HttpModule
, и все работает нормально, пока я не удалю свойство static
следующим образом
this.applicationPath = (HttpRuntime.AppDomainAppVirtualPath.Length > 1) ? HttpRuntime.AppDomainAppVirtualPath : String.Empty;
Я не знаю, как создать mocks для класса static
и свойства типа HttpRuntime.AppDomainAppVirtualPath
. context
, request
и response
были издевались над образцом кода, который я получаю от moq. Я буду признателен, если кто-нибудь сможет мне помочь в этом.
Ответы
Ответ 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 выглядит разумным решением, и я, вероятно, собираюсь использовать его на некоторых решениях в ближайшем будущем.
Ответ 5
Вы можете использовать Microsoft Fakes для этого. Это определенно решит проблему.
См. https://msdn.microsoft.com/en-us/library/hh549175.aspx
Ответ 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}