2009-12-01 34 views
23

Estoy comenzando un nuevo proyecto con NHibernate, ASP.NET MVC 2.0 y StructureMap y usando NUnit y Moq para probar. Para cada uno de mis controladores tengo un único constructor público en el que se está inyectando una ISession. La aplicación en sí funciona bien, pero en términos de pruebas unitarias, esencialmente tengo que burlarme de una ISession para probar los controladores.Mocking una ISession de NHibernate con Moq

Cuando intento para burlarse del ISession con MOQ me sale el siguiente mensaje de error:

Sólo se admiten los accesos de propiedad en las invocaciones intermedios

Parece que mi problema está a la espera Lista de usuarios del método Framework CreateQuery, pero después de buscar en Google el problema, ahora estoy más claro.

Tengo dos preguntas:

1) ¿Es este el camino equivocado para burlarse de la inyección de dependencia de un ISession

2) ¿Hay una manera de modificar el código para que pueda regresar con éxito mi lista

  [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); 
      } 

Tenga en cuenta, estoy bastante seguro de que sólo pudiera crear una lista no modificable de los usuarios (en lugar de burlarse de un usuario individual y agregarlo a una lista), pero pensé que podría dejar el código como lo tengo ahora mismo.

Además, la acción de índice de este controlador en particular ejecuta esencialmente la llamada CreateQuery imitada anteriormente para devolver todos los usuarios en la base de datos. Este es un ejemplo artificial: no lea nada en los detalles.

Gracias de antemano por su ayuda

Editar: En respuesta al comentario más abajo, estoy añadiendo la StackTrace por el error. Además, todas las propiedades de la clase User son virtuales.

TestCase 'Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView' falló: System.NotSupportedException: sólo accede a la propiedad son compatibles en las invocaciones intermedios en una configuración . Expresión no compatible framework.CreateQuery ("del usuario"). en Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall (MethodCallExpression m) en Moq.ExpressionVisitor.Visit (Expresión exp) en Moq.Mock.AutoMockPropertiesVisitor.VisitMethodCall (MethodCallExpression m) en Moq.ExpressionVisitor.Visit (Expresión exp) en Moq.Mock.AutoMockPropertiesVisitor.SetupMocks (expresión la expresión) a Moq.Mock.GetInterceptor (LambdaExpression lambda, mock Mock) en Moq.Mock. <> c__DisplayClass12 función) en Moq.Mock.Setup [T1, TResult] (mock Mock, Expresión 1 expression) at Moq.Mock 1.Setup [TResult] (Expression`1 expresión) Controllers \ UserControllerTest.cs (29,0): en Beta.Tests.Unit.Controllers.UserControllerTest.Details_InValidIndex_ReturnsNotFoundView()

+0

¿Pudo mostrar un error de pila del error? ¿Las propiedades del usuario son abstractas o virtuales? –

Respuesta

20

A continuación se muestra la solución que se me ocurrió que parece funcionar perfectamente. Una vez más, no estoy probando NHibernate y no estoy probando la base de datos; simplemente quiero probar los controladores que dependen de NHibernate. El problema con la solución inicial parece ser el hecho de que estaba llamando a un Método además de leer el miembro de la lista de la sesión en la llamada de configuración de MOQ. Interrumpí estas llamadas al dividir la solución en un QueryMock y un Session Mock (la consulta de creación devuelve un objeto IQuery). Un simulacro de transacción también era necesario, ya que es una dependencia (en mi caso) de la sesión ...

 [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

En lugar de imitar de la Session, se podría considerar la creación de una diferente Configuration para unidad de pruebas. Esta unidad de prueba Configuration utiliza una base de datos rápida en proceso como SQLite o Firebird. En la configuración del dispositivo, crea una nueva base de datos de prueba completamente desde cero, ejecuta los scripts para configurar las tablas y crea un conjunto de registros iniciales. En la configuración por prueba, se abre una transacción y, en el cierre de prueba posterior, se retrotrae la transacción para restaurar la base de datos a su estado anterior. En cierto sentido, no te estás burlando del Session, porque eso es complicado, pero te estás burlando de la base de datos real.

+0

Gracias Justicia. Definitivamente había pensado en eso y, si no puedo hacerlo funcionar, así será. Pero estoy tratando de evitar la base de datos por completo en este proyecto de prueba. Si puedo burlarme de NHibernate, creo que tendré mucho más control sobre mis pruebas ... ¡pero gracias por la sugerencia! –

+3

Desafortunadamente, la 'Sesión' de NHibernate es muy complicada cuando se trata de objetos relacionados, carga diferida, almacenamiento en caché y todas las demás cosas que hace NHibernate. Así que me saltaría el intento de burlarme de él y en su lugar intentaré burlarme de la base de datos. Es fácil para NHibernate generar un script de creación de esquema para cualquier sistema de base de datos dado a partir de sus asignaciones y luego ejecutarlo para crear una base de datos vacía con su esquema en Fixture-Setup. Desde mi propia experiencia con NHibernate y observando lo que hacen los frameworks como Rails, este es esencialmente el único camino a seguir. – yfeldblum

+0

hmm, tienes razón ... aunque sería tan bueno que no necesitamos usar un db burlado ... si ya tenemos el nhibernate que traduce nuestro modelo relacional al modelo de objeto, es algo extraño probarlo así, deberíamos poder probarlo directamente ... buenas preguntas y respuestas, aplausos :) – Marko

Cuestiones relacionadas