Издевательствование NHibernate ISession с Moq
Я запускаю новый проект с NHibernate, ASP.NET MVC 2.0 и StructureMap и используя NUnit и Moq для тестирования. Для каждого из моих контроллеров у меня есть единственный публичный конструктор, в который вводится ISession. Само приложение работает очень хорошо, но с точки зрения модульного тестирования я, по сути, должен издеваться над ISession, чтобы протестировать контроллеры.
Когда я пытаюсь Mock 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, посланный выше, чтобы вернуть всех пользователей в базу данных. Это надуманный пример - ничего не читайте в деталях.
Заранее благодарим за помощь
Изменить: в ответ на следующий комментарий я добавляю stacktrace для ошибки. Кроме того, все свойства класса User являются виртуальными.
TestCase 'Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView' failed: System.NotSupportedException: Поддерживаются только права доступа к свойствам в промежуточных вызовах на настроить. Неподдерживаемое выражение framework.CreateQuery( "от пользователя" ). в Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression м) при Moq.ExpressionVisitor.Visit(Expression exp) в Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall(MethodCallExpression м) при Moq.ExpressionVisitor.Visit(Expression exp) в Moq.Mock.AutoMockPropertiesVisitor.SetupMocks(Expression выражение) в Moq.Mock.GetInterceptor(LambdaExpression lambda, Mock mock) в Moq.Mock <. > C__DisplayClass12 2.<Setup>b__11()
at Moq.PexProtector.Invoke[T](Func
1 функции) при 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()
Ответы
Ответ 1
Ниже приведено решение, с которым, похоже, работает отлично. Опять же, я не тестирую 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);
}
Ответ 2
Вместо того, чтобы издеваться над Session
, можно подумать о настройке другого Configuration
для unit-тестов. В этом модульном тестировании Configuration
используется быстрая база данных в процессе работы, такая как SQLite или Firebird. В настройке прибора вы полностью создаете новую тестовую базу данных с нуля, запускаете скрипты для настройки таблиц и создаете набор исходных записей. В каждой тестовой настройке вы открываете транзакцию и в процессе посттестирования вы откатываете транзакцию, чтобы восстановить базу данных до ее предыдущего состояния. В некотором смысле вы не издеваетесь над Session
, потому что это становится сложно, но вы издеваетесь над реальной базой данных.
Ответ 3
В Ayende есть очень хорошая статья, как вы можете протестировать NHibernate:
http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx
веселит