Как вы издеваетесь над UnitOfWork из Rhino.Commons?

Мое приложение использует Rhino.Commons - NHRepository и UnitOfWork. Мне нравится синтаксис With.Transaction() для транзакций, и я использую его в течение некоторого времени.

Но я столкнулся с проблемой - как мне издеваться над UnitOfWork для тестирования? Особенно это доставляет мне неприятности:

With.Transaction(() => Repositories.TwinfieldSpooler.Update(spool));

Я могу смоделировать репозитории с помощью Rhino.Mocks, но как я могу легко смоделировать UnitOfWork для такого рода кода?

4 ответа

Решение

Спасибо, но я на самом деле решил игнорировать насмешки над инфраструктурой Rhino. Я нашел это сообщение Ayende http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx об использовании базы данных sqlite, перестраиваемой с каждым тестом. Это было отличное решение!

У меня была аналогичная потребность, потому что я хотел проверить логику постоянства без фактического тестирования постоянства данных. Я обнаружил, что могу издеваться UnitOfWork легко используя эти 2 строки в части моих тестов SetUp:

IUnitOfWork theStubUnitOfWork = MockRepository.GenerateStub<IUnitOfWork>();
UnitOfWork.RegisterGlobalUnitOfWork(theStubUnitOfWork);

With.Transaction использует свойство UnitOfWork.Current. UnitOfWork является статическим классом - вы не можете высмеивать его с помощью RhinoMocks.

UnitOfWork.Current является публичным статическим свойством, поэтому вы можете поменять его. К сожалению, сеттер является внутренним.

Я вижу 3 варианта для вас:

  • Измените исходный код Rhino.Commons, чтобы сделать установщик UnitOfWork.Current общедоступным, и установите его в своем модульном тесте.

  • Используйте отражение, чтобы установить UnitOfWork.Current для вашей поддельной единицы работы.

  • Поскольку UnitOfWork.Current внутренне использует Local.Data для поиска текущей транзакции, вы должны иметь возможность перейти:

    Rhino.Commons.Local.Data [UnitOfWork.CurrentUnitOfWorkKey] = myFakeUnitOfWork;

Хорошей новостью является то, что UnitOfWork.Current является IUnitOfWork, и RhinoMocks может легко подделывать интерфейсы.

Я должен закончить словами: я не очень знаком с Rhino.Commons, поэтому Айенде могла бы придумать правильный способ подделать UnitOfWork. Если это очень важно для вас, вы должны спросить в дискуссионных группах Rhino.

Просто дополнительная информация для других: Ogre Psalm33 упомянул, как заглушить UnitOfWork, но если вы также хотите, чтобы With.Transaction работал, вы можете дополнительно заглушить RhinoTransaction:

IUnitOfWork stubUnitOfWork = MockRepository.GenerateStub<IUnitOfWork>();
RhinoTransaction stubTx = MockRepository.GenerateStub<RhinoTransaction>();
stubUnitOfWork.Expect(x => x.BeginTransaction(System.Data.IsolationLevel.Unspecified)).IgnoreArguments().Return(stubTx);
UnitOfWork.RegisterGlobalUnitOfWork(stubUnitOfWork);

Я помню, как видел где-то заметку от Айенде, что он обычно использовал With.Transaction только в качестве крайней меры, когда он не мог использовать свой предпочтительный Castle Automatic Transaction Management.

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