Фальшивые фреймворки против фреймворков MS Fakes

Немного запутался в различиях Mock-фреймворков, таких как NMock и VS 2011 Fakes Framework. Проходя через MSDN, я понимаю, что Fakes позволяет имитировать ваши зависимости точно так же, как RhinoMock или NMock, однако подход отличается, Fakes генерирует код для реализации этой функциональности, а инфраструктура Mocks - нет. Так правильно ли мое понимание? Является ли подделки просто еще один Mock Framework

5 ответов

Ваш вопрос был о том, чем фреймворк MS Fakes отличается от NMock, и похоже, что другие ответы решили эту проблему, но вот еще немного информации о том, как они одинаковы и как они отличаются. NMock также похож на RhinoMocks и Moq, поэтому я группирую их с помощью NMock.

Я сразу вижу 3 основных различия между NMock/RhinoMocks/Moq и MS Fakes Framework:

  • Инфраструктура MS Fakes использует сгенерированный код, во многом как Accessors в предыдущих версиях Visual Studio, а не универсальные типы. Если вы хотите использовать фальшивый фреймворк для зависимости, вы добавляете сборку, содержащую зависимость, к ссылкам тестового проекта, а затем щелкаете по ней правой кнопкой мыши, чтобы сгенерировать двойники теста (заглушки или прокладки). Затем, когда вы тестируете, вы фактически используете эти сгенерированные классы. NMock использует дженерики для достижения той же цели (т.е. IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()). По моему мнению, подход MS Fakes Framework запрещает навигацию по коду и рефакторинг изнутри тестов, так как вы фактически работаете с сгенерированным классом, а не с реальным интерфейсом.

  • Инфраструктура MS Fakes предоставляет заглушки и кроты (прокладки), тогда как NMock, RhinoMocks и Moq предоставляют заглушки и макеты. Я действительно не понимаю решение MS не включать насмешки, и я лично не фанат родинок по причинам, описанным ниже.

  • В рамках фальшивой структуры MS вы предоставляете альтернативную реализацию методов, которые вы хотите заблокировать. В этих альтернативных реализациях вы можете указать возвращаемые значения и отслеживать информацию о том, как или был вызван метод. С NMock, RhinoMocks и Moq вы генерируете фиктивный объект, а затем используете этот объект для указания возвращаемых значений с заглушками или для отслеживания взаимодействий (были ли вызваны методы). Я считаю, что подход к подделкам MS более сложный и менее выразительный.

Чтобы прояснить разницу в том, что предоставляют фреймворки: NMock, RhinoMocks и Moq предоставляют два типа тестовых двойников (заглушки и макеты). Поддельная структура предоставляет окурки и родинки (они называют их прокладками), и, к сожалению, не включает насмешки. Чтобы понять различия и сходства между NMock и MS Fakes, полезно понять, что представляют собой следующие типы тестов:

Заглушки: Заглушки используются, когда вам необходимо предоставить значения для методов или свойств, которые будут запрашиваться в вашем тесте, удваивается в тестируемом методе. Например, когда мой тестируемый метод вызывает метод DoesStudentExist () теста IStudentRepository double, я хочу, чтобы он возвратил true.

Идея заглушек в NMock и MS fakes одинакова, но с NMock вы бы сделали что-то вроде этого:

Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));

А с MSFakes вы бы сделали что-то вроде этого:

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
    DoesStudentExistInt32 = (studentId) => { return new Student(); }
};

Обратите внимание, что в примере MS Fakes вы создаете совершенно новую реализацию для метода DoesStudentExist (обратите внимание, что он называется DoesStudentExistInt32, потому что инфраструктура fakes добавляет типы данных параметров к именам методов при создании объектов-заглушек, я думаю, что это затеняет ясность тесты). Честно говоря, реализация NMock также вызывает ошибки, потому что она использует строку для определения имени метода. (Простите, если я неправильно понял, как NMock предназначен для использования.) Этот подход действительно запрещает рефакторинг, и по этой причине я настоятельно рекомендую RhinoMocks или Moq вместо NMock.

Mocks: Mocks используются для проверки взаимодействия между тестируемым методом и его зависимостями. С NMock вы делаете это, устанавливая ожидания, подобные этому:

Expect.Once.On(mockStudentRepository).Method("Find").With(123);

Это еще одна причина, по которой я предпочитаю RhinoMocks и Moq, а не NMock. NMock использует более старый стиль ожидания, тогда как RhinoMocks и Moq поддерживают подход Arrange/Act/Assert, где вы указываете ожидаемые взаимодействия в качестве утверждений в конце теста, как этот:

stubStudentRepository.AssertWasCalled( x => x.Find(123));

Опять же, обратите внимание, что RhinoMocks использует лямбду вместо строки для идентификации метода. Фреймворк MS Fakes вообще не предоставляет макетов. Это означает, что в ваших заглушенных реализациях (см. Описание заглушек выше) вы должны установить переменные, которые, как вы позже убедитесь, были установлены правильно. Это будет выглядеть примерно так:

bool wasFindCalled = false;

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() 
{
    DoesStudentExistInt32 = (studentId) => 
        { 
            wasFindCalled = true;
            return new Student(); 
        }
};

classUnderTest.MethodUnderTest();

Assert.IsTrue(wasFindCalled);

Я нахожу этот подход немного запутанным, так как вы должны отслеживать вызов в заглушке, а затем утверждать его позже в тесте. Я считаю, что примеры NMock, и особенно RhinoMocks, более выразительны.

Родинки (Shims): Честно говоря, я не люблю родинок из-за их потенциального злоупотребления. Одна из вещей, которые мне так нравятся в модульном тестировании (и в частности в TDD), заключается в том, что тестирование вашего кода помогает вам понять, где вы написали плохой код. Это потому, что тестирование плохо написанного кода затруднительно. Это не так при использовании родинок, потому что родинки фактически предназначены для того, чтобы вы могли проверять зависимости, которые не вводятся, или тестировать частные методы. Они работают аналогично заглушкам, за исключением того, что вы используете ShimsContext следующим образом:

using (ShimsContext.Create())
{
    System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}

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

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

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

Вы правы, но это еще не история. Наиболее важные вещи, которые нужно убрать из этого ответа:

  1. Ваша архитектура должна должным образом использовать заглушки и внедрение зависимостей, а не полагаться на костыли подделок и издевательств

  2. Подделки и макеты полезны для тестирования кода, который вы не должны или не можете изменить, например:

    • Устаревший код, который не использует (или эффективно использует) заглушки
    • Сторонние API
    • Ресурсы, для которых у вас нет исходного кода

Shims (известный как "Родинки" во время разработки) - это действительно насмешливая основа, которая действует путем обхода вызовов. Вместо кропотливого создания макета (да, даже использование Moq относительно болезненно!), Шиммы просто используют уже созданный объект производственного кода. Прокладки просто перенаправляют вызов от производственной цели к тестовому делегату.

Заглушки генерируются из интерфейсов в целевом проекте. Объект Stub - это всего лишь реализация интерфейса. Преимущество использования типа заглушки состоит в том, что вы можете быстро создать заглушку, не загромождая ваш тестовый проект многими одноразовыми заглушками, не говоря уже о том, что вы тратите время на их создание. Конечно, вы все равно должны создавать конкретные заглушки для использования во многих тестах.

Эффективная реализация Fakes (Shims, Mocks и Stub) требует небольшого привыкания, но стоит затраченных усилий. Я лично сэкономил недели разработки, используя типы Shims/Mole, Mocks и Stub. Я надеюсь, что вы получите от этой технологии столько же удовольствия, сколько и я!

Насколько я понимаю, команда Visual Studio хотела избежать конкуренции с различными фиктивными библиотеками, доступными для.NET. MS часто сталкивается с такими трудными решениями. Они прокляты, если не предоставляют определенную функциональность ("почему MS не предоставляет нам фиктивную библиотеку; насмешки являются таким распространенным требованием?") И прокляты, если они это делают ("почему Microsoft ведет себя так агрессивно и ведет сторонников естественного рынка нет? ") Очень часто, но не всегда, они решают воздерживаться от простого предоставления собственной альтернативы доступным и хорошо принятым технологиям. Это, кажется, имеет место здесь.

Функция подделки в Fakes действительно очень полезна. Конечно, есть опасности. Требуется некоторая дисциплина, чтобы убедиться, что вы используете это только там, где это необходимо. Тем не менее, он заполняет большой пробел. Моя главная жалоба заключается в том, что она поставляется только с Ultimate редакцией VS 2012 и, следовательно, будет доступна только для части сообщества разработчиков.NET. Как жаль.

Подделки включают в себя два разных типа "поддельных" объектов. Первый, называемый "заглушкой", по сути, представляет собой автоматически генерируемый манекен, поведение по умолчанию которого можно (и обычно) можно переопределить, чтобы сделать его более интересным. Однако в нем отсутствуют некоторые функции, которые предлагает большинство доступных в настоящее время макетов. Например, если вы хотите проверить, был ли вызван метод для экземпляра-заглушки, вам необходимо добавить логику для этого самостоятельно. По сути, если вы сейчас создаете свои собственные макеты вручную, заглушки, вероятно, кажутся улучшением. Однако, если вы уже используете более полнофункциональный макет, вы можете почувствовать, что в заглушках Fakes отсутствуют некоторые важные элементы.

Другая категория объектов, предлагаемая Fakes, называемая "шим", предоставляет механизм для замены поведения зависимостей, которые не были (или не могут быть) отсоединены адекватно для стандартной замены с помощью имитаций. AFAIK, TypeMock - единственная из основных фреймворков, которая в настоящее время предлагает такую ​​функциональность.

Кстати, если вы уже опробовали Moles прежде, Fakes - это по сути то же самое, наконец-то сделав свой путь из Microsoft Research в настоящий продукт.

Относительно поддельных (Shim + Stub) объектов, это было хорошо определено выше, хотя я думаю, что последний абзац в последнем комментарии суммирует всю ситуацию довольно хорошо.

Хотя многие люди утверждают, что поддельные (Shim + Stub) объекты являются хорошими ресурсами в некоторых случаях модульного тестирования, недостатком является то, что независимо от того, используете ли вы Visual Studio 2012 или Visual Studio 2013, эти параметры доступны ТОЛЬКО с Premium или Ultimate версиями. Итак, это означает, что вы НЕ БУДЕТЕ запускать ЛЮБЫЕ из этих подделок (Shim + Stub) в любой версии Pro.

Возможно, вы увидите опцию меню Fakes (Shim + Stub) в Pro-версиях, но будьте осторожны, есть некоторые довольно сильные шансы, что вы ничего не получите... Это не сгенерирует ошибку компиляции, сообщающую вам что-то важное отсутствует, вариантов просто нет, так что не теряйте времени...

Это важный фактор, который необходимо учитывать в команде разработчиков, особенно если один использует Ultimate, а остальные используют Pro-версию... С другой стороны, Moq можно легко установить через Nuget независимо от того, какую версию Visual Studio вы используете. У меня не было проблем с использованием Moq, ключ к любому инструменту - знать, для чего они используются и как их правильно использовать;)

Другие вопросы по тегам