2009-12-01 2 views
23

Я начинаю новый проект с NHibernate, ASP.NET MVC 2.0 и StructureMap и используя NUnit и Moq для тестирования. Для каждого из моих контроллеров у меня есть единственный публичный конструктор, в который вводится ISession. Само приложение работает очень хорошо, но с точки зрения модульного тестирования я, по сути, должен издеваться над ISession, чтобы протестировать контроллеры.Стыковка NHibernate ISession с Moq

При попытке дразнит ISession с MOQ я получаю следующее сообщение об ошибке:

только доступы собственности поддерживаются в промежуточных заклятиях

Оказывается, что моя проблема ожидает список пользователей из метода CreateQuery Framework, но после того, как я перешел к проблеме, я теперь более ясен.

У меня есть два вопроса:

1) Является ли это неправильный способ издеваться инъекции зависимостей из ISession

2) Есть ли способ изменить код, чтобы он мог успешно вернуть мой список

  [Test] 
      public void DummyTest() 
      { 

       var mock = new Mock<ISession>(); 
       var loc = new Mock<User>(); 
       loc.SetupGet(x => x.ID).Returns(2); 
       loc.SetupGet(x => x.FirstName).Returns("John"); 
       loc.SetupGet(x => x.LastName).Returns("Peterson"); 

       var lst = new List<User> {loc.Object}; 
       mock.Setup(framework => framework.CreateQuery("from User").List<User>()).Returns(lst); 

       var controller = new UsersController(mock.Object); 
       var result = controller.Index() as ViewResult; 
       Assert.IsNotNull(result.ViewData); 
      } 

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

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

Заранее спасибо за помощь

Edit: В ответ на комментарии ниже, я добавляю в StackTrace для ошибки. Кроме того, все свойства класса User являются виртуальными.

TestCase 'Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView' не удалось: System.NotSupportedException: только доступы собственности поддерживаются в промежуточных вызовах на установки. Неподдерживаемое выражение framework.CreateQuery («от пользователя»). на Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall (MethodCallExpression м) на Moq.ExpressionVisitor.Visit (Expression ехр) при Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall (MethodCallExpression м) на Moq.ExpressionVisitor.Visit (Выражение ехра) при Moq.Mock.AutoMockPropertiesVisitor.SetupMocks (выражение выражения) в Moq.Mock.GetInterceptor (LambdaExpression лямбды, Ложная макет) при Moq.Mock. <> c__DisplayClass12 функция) при Moq.Mock.Setup [T1, TResult] (Mock Mock, Выражение 1 expression) at Moq.Mock 1.Setup [TResult] ( выражение Expression`1) Контроллеры \ UserControllerTest.CS (29,0): в Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView()

+0

Не могли бы вы отобразить стопку ошибки? Являются ли свойства пользователя абстрактными или виртуальными? –

ответ

20

Ниже приведено решение, с которым, как представляется, работает отлично. Опять же, я не тестирую NHibernate, и я не тестирую базу данных - я просто хочу проверить контроллеры, которые зависят от NHibernate. Проблема с первоначальным решением, по-видимому, заключается в том, что я вызывал метод, а также читал член List из сеанса в установочном вызове MOQ. Я разбил эти вызовы, разбив решение на QueryMock и сеанс Mock (создать запрос возвращает объект IQuery). Макет сделка была также необходима, как это зависимость (в моем случае) сессии ...

 [Test] 
     public void DummyTest() 
     { 
      var userList = new List<User>() { new User() { ID = 2, FirstName = "John", LastName = "Peterson" } }; 
      var sessionMock = new Mock<ISession>(); 
      var queryMock = new Mock<IQuery>(); 
      var transactionMock = new Mock<ITransaction>(); 

      sessionMock.SetupGet(x => x.Transaction).Returns(transactionMock.Object); 
      sessionMock.Setup(session => session.CreateQuery("from User")).Returns(queryMock.Object); 
      queryMock.Setup(x => x.List<User>()).Returns(userList); 

      var controller = new UsersController(sessionMock.Object); 
      var result = controller.Index() as ViewResult; 
      Assert.IsNotNull(result.ViewData); 
     } 
18

Вместо насмешливый Session, можно было бы рассмотреть вопрос о создании другого Configuration для юнит-тестов. В этом модульном тестировании Configuration используется быстрая база данных, например SQLite или Firebird. В настройке прибора вы полностью создаете новую тестовую базу данных с нуля, запускаете скрипты для настройки таблиц и создаете набор исходных записей. В каждой тестовой настройке вы открываете транзакцию и в процессе посттестирования вы откатываете транзакцию, чтобы восстановить базу данных до ее предыдущего состояния. В каком-то смысле вы не издеваетесь над Session, потому что это сложно, но вы издеваетесь над реальной базой данных.

+0

Спасибо юстиции. Я определенно думал об этом, и, если я не могу получить эту работу, это будет так, как я. Но я пытаюсь избежать базы данных в целом в этом тестовом проекте. Если я могу издеваться над NHibernate, я чувствую, что у меня будет гораздо больше контроля над моими испытаниями ... но спасибо за предложение! –

+3

К сожалению, сеанс NHibernate очень сложный, когда дело касается связанных объектов, отложенной загрузки, кеширования и всех других вещей, которые делает NHibernate. Поэтому я просто пропустил бы попытку издеваться над этим и вместо этого попытался издеваться над базой данных. Для NHibernate легко создать сценарий создания схемы для любой системы баз данных из ваших сопоставлений, а затем для выполнения этого сценария для создания пустой базы данных с вашей схемой при настройке прибора. Из моего собственного опыта работы с NHibernate и наблюдения за рамками, такими как Rails, это, по сути, единственный путь. – yfeldblum

+0

хм, вы правы ... хотя это было бы так приятно, что нам не нужно использовать какой-то издевавшийся db ... если у нас уже есть nhibernate, который переводит нашу реляционную модель в объектную модель, это довольно странно тестировать например, мы должны проверить его непосредственно ... приятный вопрос и ответы, приветствия :) – Marko

3

Существует очень хорошая статья от Ayende, как вы можете протестировать NHibernate:

http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx

ура

+0

Хорошая статья :), но это полезно, если вы действительно хотите протестировать свою логику сохранения не тогда, когда хотите протестировать другой компонент. – Beatles1692

Смежные вопросы