Макет статического свойства с moq - PullRequest
41 голосов
/ 10 марта 2010

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

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

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

Ответы [ 6 ]

61 голосов
/ 10 марта 2010

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

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

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);
}

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

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

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

11 голосов
/ 10 марта 2010

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

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

// 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 голосов
/ 10 марта 2010

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

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

2 голосов
/ 21 октября 2013

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

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

1 голос
/ 20 июля 2016

Вы можете использовать Microsoft Fakes для этого. Это определенно решит проблему. См. https://msdn.microsoft.com/en-us/library/hh549175.aspx

0 голосов
/ 06 февраля 2019

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

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

    использование (Microsoft.QualityTools.Testing.Fakes.ShimsContext.Create ()) { System.Web.Fakes.ShimHttpRuntime.AppDomainAppVirtualPathGet = () => "/"; // Делать то, что когда-либо нужно, поддельный AppDomainAppVirtualPath }

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