13 October 2008

Moq - Stubbing is back!

Мабуть, я  вже усім прожужав вуха про своє кохання – це Moq. Те ще це кохання може засвідчити, той факт що я безкоштовно переклав 300 юніт-тестів з Rhino.Mocks на Moq, для свого поточного проекту.

Головна фішка Moq це його синтаксис. Я не буду наводити приклади, але це щось! Усілякі рекоди/реплай в минулому.

Але була і ложка дьогтю, для мене завжди було не зрозуміле повне ігнорування факту, що іноді таки потрібен стаббінг.

Але це було! А тепер Mog 2.6 – і підтримка стаббінгу. За лінкою можна все прочитати.


Декілька фактів

  • Підтримує тільки синтаксис побудований на Lambda Expressions, а отже .NET 2.0 в прольоті;
  • Все типізоване, все підтримує інтелісенс;
  • Саме ця бібліотека використовується Microsoft для публічної версії MVC Framework. Внутрішня використовує щось своє, виплекане в тернях Microsoft;

Коментарі

# status_alexus said:

> Усілякі рекоди/реплай в минулому.

Я сам немного использовал на проекте Rhino.Mocks в основном по двум причинам:

- меня его рекомендовали

- проект open source и разработчик ведет только одну основную ветку

Синтаксис мне показался достаточно прозрачным. Ничего военного. Хотя возможно я его очень мало использовал, поэтому он мне не успел надоесть :)

К тому же на момент разработки юнит тестов мы еще были на .NET 1.1, но это в прошлом. Сейчас проект переведен на .NET 3.5

Посмотрел на синтаксис Moq. Я как раз создавал именно stab-объекты.

Все просто и без всяких дополнительных заморочек с асинхронными вызовами, изменением поведения объекта во время его использования в тесте и т.п.

Насколько я понял что Record/Replay синтаксис был заменен использованием Lambda-выражений:

var context = new Mock<HttpContextBase>();

context.Expect(c => c.Response.ContentType).Returns("application/xml");

Что ж, довольно любопытно. Заглянул на сайт Rhino.Mocks и обнаружил что он тоже поддерживает схожий (либо идентичный) синтаксис:

var mockUserRepository = MockRepository.GenerateMock<IUserRepository>();

var stubbedSmsSender = MockRepository.GenerateStub<ISmsSender>();

var theUser = new User{HashedPassword = "this is not hashed password"};    

mockUserRepository.Stub(x => x.GetUserByName("ayende")).Return(theUser);

mockUserRepository.Expect( x => x.Save(theUser) );

Кроме всего мне еще нравится дополнительное управление Expectation'ами. Получается, что я могу не только определять то как будет вести себя объект, который я построил, но и могу задать правила которые декларируют как этот объект будут использовать.

Михаил, к сожалению по твоему посту я так и не понял чем же Moq лучше.

14 October 08 at 3:10 AM
# Mike Chaliy said:

Невже кохання потрібно пояснювати?

Жарт

Я ніколи не писав що Moq кращий за Rhino.Mocks. Я завжди рекомендую Rhino.Mocks, додаючи що особисто я б обрав Moq. Це легко пояснити, Rhino.Mocks це дефакто стандарт, в нього є комуніті. У той самий час Moq пише команда (це добре), але в деяких випадках вони роблять фанатичні заяви, на кшталт того що вони не хочуть підтримувати стаби (це погано). У них менша комуніті (погано), хоча і зростає набагато швидше за Ріно. Їхні погляди більш менш одного напрямку з моїми(для мене це добре).

Зараз ситаксис з лямюда експерешенами не підтримує аби ледачий... Навіть NMock і той якось підтримує...

Якщо тебе цікавить що саме і тільки особисто мені не подобається в Ріно, не проблема, я відповім, але я ще раз підкреслю, я нікого не агітую переганяти 300 тестів на Moq ;).

Отже почнемо:

1) Первірка за допомогою Collback, Ріно чомусь вважає що для того щоб первірити чи працює метод булева достатньо. Це не так. Я вже писав про це.

2) Collback для стаббінгу, я довго бився як зберегти локальне значення за допомогою Collback. В якихось випадках він викликався, в якихось ні. Якщо ця проблема зацікавить, я спробую зарепродьюсити це. Так вже не пам'ятаю.

3) Return для стаббінгу, тобто так щоб можна було виконувати код на момент вилику, щось на кшталт

mockUserRepository.Stub(x => x.Test())

.Return(() => "return something based on input");

4) Ще буди якісь проблеми коли не робив

using (mockRepository.Record())

тобто не використовував рекорд/реплай, проблеми були коли у залежності, є залежність, яка щось хоче на момент ініціалізації. Хоча чесно кажучи я зараз не можу відтворити цього в пам'яті, якщо зацікавить то зможу.

5) На той час коли мені все це було потрібно в релізі Ріно ще не було підтримки лямбда експершенів.

Було ще щось, але це не суттєво, з усим цим можна боротись.

Тепер аналогічний список для Moq. Хоча аналогчним він не може бути з Ріно я працював на багато більше.

1) Їхня підтримка стаббігну, це вже в минулому, але ще місяц потому ця проблема була дуже актуальна.

2) test.Expect( x => x.Save(null) ); не означає що я можу туди запхнути будь що. Це приводить до великих колбасін, test.Expect( x => x.Save(It.IsNull<String>()) );. Мене це дещо вбиває.

3) Мала комуніті, всі помилки Рхіно швидко знаходяться в інтеті, для Moq я витрачав набагато часу для пошуку рішення.

4) Ще зелена, дуже зелена.

5) Відсутність документашки... тільки декілька прикладів, та формуи.

6) Фанатичні розробники....

Сто відсотково є щось ще, але я не збирався робити таке порівнняння, тобто збирався, а ле окремим постом, і з участю ще декліькох ліб, плюс найцікавіше ліби для Java та Ruby, останне найцікавыше!

14 October 08 at 3:57 AM
# eisernWolf said:

С ходу не понравилось пока только одно - по сути корни тут лежат в DotNetMock (который так и застыл на версии 0.8.0 для .Net Framework 1.1). Выдают это названия методов хотя бы, да и сам подход. Тем не менее, про него нету даже упоминания на страничке проекта. Обидно за свой любимый фреймворк... Действительно, вся эта эйфория разработчиков вокруг Moq несколько напрягает.

22 October 08 at 2:41 PM
# Mike Chaliy said:

>>по сути корни тут лежат в DotNetMock

Ні, або ти щось плутаєш, або вони різів зі 200 все переписали. В них повністю різний кодбейз, я жодної подібності не знайшов, вони використовують різні бібліотеки для генерування (DotNetMock  - Refly, Moq - Castle DynamicProxy), для тестування (DotNetMock  - NUnit, Moq - xUnit), тощо.

22 October 08 at 3:09 PM
# eisernWolf said:

>>В них повністю різний кодбейз

Так. Але ж я гавару пра канцэпцыю. Тыповы DotNetMock сцэнар:

  MockVitalsView view = new MockVitalsView();

  VitalsController controller = new VitalsController(view);

  view.Name = "";

  view.SSN = "123-45-6789";

  view.SetExpectedErrorMessage(controller.ERROR_MESSAGE_BAD_NAME);

  Assertion.Assert(controller.OnOk() == false );

  view.Verify();

Нічога не нагадвае? :) Мне такі падыход значна больш падабаецца, чым "record/reply weirdness". Мой уклад да DotNetMock: http://www.gotdotnet.ru/Downloads/Examples/492876.aspx Але зараз гэта ўжо бессэнсоўна. Ёсьць Moq. :)

23 October 08 at 7:50 AM
Анонімні коментарі деактивовані. Увійдіть або Зареєструйтесь щоб мати доступ до ресурсів Спільноти.

About Mike Chaliy

Вчу українську, багато працюю. Цікавлюсь моделюванням небезпек. Більшість часу витрачаю на .Net.