Почему собственность, которую я хочу высмеять, должна быть виртуальной? - PullRequest
38 голосов
/ 15 апреля 2011

Я провожу модульное тестирование и проверяю некоторые свойства, используя Moq .

Теперь это тест Controller (ASP.NET MVC 3). Мои контроллеры происходят от контроллера abstract , называемого AbstractController .

Этот контроллер зависит от контекста Http (для выполнения таких задач, как создание тем, логика, относящаяся к домену на основе заголовков HTTP HOST и т. Д.).

Это делается с помощью свойства WebSiteSettings :

public abstract class AbstractController : Controller
{
   public WebSiteSettings WebSiteSettings { get; private set; }

   // other code
}

Обратите внимание на приватный набор - ctor устанавливает его. Итак, я изменил его на используемый интерфейс, и вот что я высмеял:

public IWebSiteSettings WebSiteSettings { get; private set; }

Затем я создал «FakeWebSiteSettings», который макетирует контекст Http, чтобы он мог читать заголовки HTTP.

Проблема в том, что когда я запускаю тест, я получаю NotSupportedException:

Неверная настройка для не виртуального (переопределяемого в VB) члена: x => x.WebSiteSettings

Вот соответствующий код насмешки:

var mockWebSiteSettings = new Mock<FakeWebSiteSettings>();
var mockController = new Mock<MyController>(SomeRepository);
mockController.Setup(x => x.WebSiteSettings).Returns(mockWebSiteSettings.Object);

_controller = mockController.Object;

var httpContextBase = MvcMockHelpers.FakeHttpContext();
httpContextBase.Setup(x => x.Request.ServerVariables).Returns(new NameValueCollection
    {
        {"HTTP_HOST","localhost.www.mydomain.com"}, 
});
_controller.SetFakeControllerContext(httpContextBase.Object);

Если я сделаю свойство WebsiteSettings virtual - тест пройден.

Но я не могу понять, зачем мне это нужно. Я на самом деле не переопределяю свойство, я просто высмеиваю, как оно настроено.

Я что-то упустил или делаю это неправильно?

Ответы [ 4 ]

58 голосов
/ 15 апреля 2011

Moq и другие подобные фреймворки могут только макетировать интерфейсы, абстрактные методы / свойства (на абстрактных классах) или виртуальные методы / свойства на конкретных классах.

Это потому, что он генерирует прокси, который будет реализовывать интерфейс или создавать производный класс, который переопределяет эти переопределяемые методы для перехвата вызовов.

4 голосов
/ 10 июня 2013

Я создал интерфейс и класс-оболочку.Например,

    public interface IWebClient
    {
        string DownloadString(string url);
    }

    public class WebClient : IWebClient
    {
        private readonly System.Net.WebClient _webClient = new System.Net.WebClient();

        public string DownloadString(string url)
        {
            return _webClient.DownloadString(url);
        }
    }

, а затем в своих модульных тестах просто смоделируйте интерфейс:

        var mockWebClient = new Mock<IWebClient>();

Очевидно, что вам может понадобиться включить больше свойств / методов.Но делает ли это трюк?

Еще один полезный трюк для других насмешливых проблем, таких как изменение текущего времени даты (я всегда использую время в формате UTC):

public interface IDateTimeUtcNowProvider
{
    DateTime UtcNow { get; } 
}

public class DateTimeUtcNowProvider : IDateTimeUtcNowProvider
{
    public DateTime UtcNow { get { return DateTime.UtcNow; } }
}

например, если у тебя есть службакоторый запускается каждые x минут, вы можете просто смоделировать IDateTimeProvider и вернуть время, которое позже, чтобы проверить, что служба снова запущена ... или что-то еще.

3 голосов
/ 27 августа 2012

«Так ... что я сделал, это единственный способ?»

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

0 голосов
/ 27 декабря 2012

Хотя все, что было сказано ранее, является правдой, стоит знать, что подход с прокси-копированием (как и тот, который использует moq) не единственный возможный.

Проверьте http://www.typemock.com/, чтобы найти исчерпывающее решение, позволяющее имитировать запечатанные классы, не виртуальные методы и т. Д. Довольно мощно.

...