Mocks, Mocking, Mockers y SharePoint

 


Alguien ha intentado usar Mocks para pruebas unitarias (“Unit Test”) con SharePoint?


A ver si nos entendemos. Supongo que Unit Test no es desconocido… dicho en palabras sencillas, es la forma que nosotros, pobres desarrolladores de software, tenemos para asegurarnos a nosotros mismos (pobres ilusos) y al mundo exterior (a nuestros clientes, para que nos paguen más dinero) que no estamos metiendo las patas de una forma vergonzosa. Unit Test tienen varias ventajas: acallar nuestros remordimientos pues no entregamos software sin ser probado apropiadamente, asegurarnos que nada se ha roto cuando cambiamos la lógica interna del software, garantizando que todo seguirá funcionando más o menos bien, tal como ocurría antes de hacer el cambio, poder ejecutar las pruebas automáticamente después de cada compilación (TFS de Microsoft, NAnt), etc., etc., etc.


Hay un montón de herramientas para hacer Unit Test regadas por Internet (MbUnit, NUnit, csUnit, TestDriven.net) e, inclusive, las tenemos incluidas en nuestra herramienta de programación favorita (en la versión Team Foundation Server Developer de Visual Studio 2005/2008, por la que hay que pagar bastante dinero para hacer lo que se puede encontrar gratis en Internet). Y un montón de teoría y teoréticos que nos intentan convencer que hacer Unit Test es lo mas importante en desarrollo de software después del estamento “if”. Todo muy interesante y muy importante, pero con un solo problema: todo el software de ayuda y todas las teorías al respecto están hechas para trabajar con clases que funcionan por sí mismas:


Nota: las imágenes me las he robado del sitio de TypeMock.NET sin permiso de los autores.


La imagen muestra una clase nuestra (“Production Class”) que es “testeada” por medio de otra clase (“Unit Test”). Desafortunadamente, la realidad es diferente, y sobre todo la realidad cuando estás trabajando con SharePoint (o con cualquier otro servidor “externo”):


En este caso, los datos que el Unit Test recibe son basados en sistemas “externos” (Data Bases, SharePoint, etc), que requieren configuración, y que, a su vez, dependen de otros sistemas externos (SharePoint depende de SQL, por ejemplo). Esto produce tres problemas para el Unit Test:


1 – Repetitividad: el sistema externo tiene que mantenerse con los mismos datos, de tal forma que los datos que el Unit Test espera (“Expected values”) para comparar con los datos calculados (“Actual values”) sean consistentes a lo largo del tiempo: si quieres ejecutar tus Pruebas Unitarias dentro de un año, tienes que garantizar que SharePoint tenga dentro de un año los mismos datos.


2 – Uso en grupo: Es normal que cuando estas desarrollando con SharePoint, cada desarrollador tenga su propia copia local de SharePoint (y, con frecuencia, de SQL), por eso de que los ensamblados de SharePoint no se pueden usar fuera del servidor, por eso de que si haciendo cosas raras te cargas a SharePoint no quieres detener el trabajo de todo el mundo, y por eso de que Microsoft nunca ha podido darnos una depuración remota que funcione. Para garantizar que los Unit Test (que son iguales para todos los desarrolladores) produzcan los mismos resultados, hay que garantizar que todas las copias locales de SharePoint sean idénticas


3 – hmmmm… el tercer punto… tenía un tercer punto, pero se me olvido… será por eso de que las células grises se agotan a pasos agigantados…


En cualquier caso, la respuesta para el problema es un “Mock”: hacerle creer a tus clases que están recibiendo la información de una fuente “exterior”, cuando en realidad están recibiéndola desde otra clase “falsa” que has creado tu mismo:


Ideal: puedes garantizar que los datos a consultar siempre sean iguales en el tiempo y para todos los desarrolladores!


Hay varias herramientas (gratis y comerciales) para crear Mocks (Rhino Mocks, TypeMock.Net, EasyMock.NET, NMock, NMock2, entre otras) unas mejores que otras, unas más fáciles de usar que otras, todas con el mismo problema: es prácticamente imposible utilizarlas para “simular” a SharePoint. Veamos:


Una clase con un método (bastante idiota) que nos puede servir de ejemplo:


     public string GetCurrentUserName(HttpContext myContext)
     {
         SPWeb myWeb = SPControl.GetContextWeb(myContext);
         SPUser myUser = myWeb.CurrentUser;
         return myUser.LoginName;
     }


El método recibe el HttpContext de una WebPart, por ejemplo, y retorna el nombre del usuario actual. Ahora el método de Prueba Unitaria, tal como es generado por Visual Studio 2005:


     [DeploymentItem(“TestConsoleApplication1.exe”)]
     [TestMethod()]
     public void GetCurrentUserNameTest()
     {
         object target = TestProject1.TestConsoleApplication1_Class1Accessor.CreatePrivate();

         TestProject1.TestConsoleApplication1_Class1Accessor accessor = new TestProject1.TestConsoleApplication1_Class1Accessor(target);

         HttpContext myContext = null; // TODO: Inicializar en un valor adecuado

         string expected = null;
         string actual;

         actual = accessor.GetCurrentUserName(myContext);

         Assert.AreEqual(expected, actual, “TestConsoleApplication1.Class1.GetCurrentUserName no devolvió el valor esperado.”);
         Assert.Inconclusive(“Verifique la exactitud de este método de prueba.”);
     }


El problema es visible inmediatamente: el objeto “myContext” tiene que ser inicializado para poder utilizar el método; este es el trabajo que tiene que hacer un Mock: crear un objeto “falso” que tenga el mismo contenido del objeto “verdadero”, pero sin tener que utilizar a SharePoint. Para aquellos masoquistas interesados en saber cómo se puede programar este tipo de Mocks, hay un ejemplo en internet que utiliza algo así como 300 líneas de código para mockear un HttpContext (“Mocking HttpContext using TypeMock.Net“).


Todo el rollo que estoy escribiendo se refiere precisamente a este problema: si para escribir un Unit Test (8 líneas de código), tengo que agregar otras 300 solamente para falsificar un HttpContext, me voy a pasar 95% del (escaso) tiempo que tengo disponible para crear código en crear clases falsas… sin decir nada de las otras mil y pico clases de SharePoint que también habría que mockear…


Como decía al principio, para un pobre pica-código como yo, que no tiene mucha idea sobre el trabajo que hacen los señores (y damas) mayores que se ocupan de hacer pruebas de software, y que solamente quiere hacer un Unit Test sencillito para SharePoint, esto es demasiado trabajo. No sería posible que alguien nos produjera una librería de Mocks para SharePoint y un FrameWork para utilizarla, compilada y lista para ser usada (aunque la tengamos que comprar), de tal forma que podamos hacer nuestro trabajo (programar y probar SharePoint) de una forma fácil y rápida?


Se aceptan sugerencias…


Gustavo – http://www.gavd.net/servers/
Escriba un Comentario que me haga reir…

16 comentarios en “Mocks, Mocking, Mockers y SharePoint”

  1. Has usado rhino? los demas que comentas no los conozco a fondo, pero el concepto de typemock es completamente distinto a rhino, que se basa en generics.
    Con rhino tendras que saber y asignar todos los metodos del objeto que devuelvan un valor a la clase testeada, pero eso es casi imposible de mejorar.
    Prueba rhino y veras que para este caso es mucho mas adecuado que typemock.

  2. Hola Oscar. Si, lo he usado (lo puedes ver en la lista de Mockers en el articulo), y mi problema es precisamente lo que comentas: “Con rhino tendrás que saber y asignar todos los métodos del objeto que devuelvan un valor a la clase testeada”… imagínate hacer una librería de mocks para SharePoint (más de 1000 clases, con una cantidad de métodos y propiedades que ni siquiera Microsoft sabe cuántos son)… eso te va a costar unos cuantos años de trabajo.
    Mi idea va mas dirigida a una especie de wysiwyg Mocker: en un servidor con SharePoint instancias y usas una clase, y con una especie de “Record and Play” creas el Mock que necesitas (usando reflexión?) con los valores que necesitas y todos los otros con valores por defecto (o null), de tal forma que no tengas que meterte en las complicaciones de conocer la estructura del objeto… es solamente un idea…

  3. Si,pero la verdad que no te entiendo.Lo que comentas de Record and Play lo puedes hacer perfectamente con lo que ya hay,no se por que lo de wysiwyg ,solo como digo debes asignar los valores a metodos que devuelven algun parametro.Si no los sabes el mock ya te lo va diciendo, y lo de valores por defecto son un par de lineas de codigo.
    Y si pretendes que alguien cree esas clases,piensalo y veras que no es mantenible.

    Resumiendo, el ejemplo que pones del nombre de usuario,con rhino no son 300 sino como mucho 10 lineas en el mock.

  4. Gustavo … estoy 100% de acuerdo contigo y mas alla de la tecnologia de “mockeo” (no se si se puede configurar el verbo “to mock”) el problema, como tu dices, es tratar de reproducir todo el entorno completo de MOSS para las pruebas …

    Me hace acordar a tratar de desarrollar con pruebas unitarias, en un entorno de Biztalk. Hasta hace un tiempo, era casi imposible, sin embargo hoy existen algunas opciones 😉

    Estoy contigo en que no se si merece la pena invertir el 95% del tiempo en crear un conjunto de Mock Objects para Moss, solo para un proyecto, pero ¿has pensado en crear un proyecto de este tipo en CodePlex y ver si se suma la gente? yo tengo a un par de compañeros de Avanade que se suman seguro !!!

    Saludos y happy testing

  5. Es un trabajo de chinos intentar crear una libería de mocks para un producto tan grande y con tantas papeletas para cambiar en el futuro.

    Lo más recomendabe es extraer el código más crítico de la aplicación a una clase que no tenga dependencias con el framework de SharePoint, sino a través de alguna abstracción que tú crees.

    Microsoft no va a refactorizar el código de sus productos para facilitar el testeo unitario, porque gran parte del código existente en las empresas dejaría de funcionar.
    La única esperanza es que creen un mecanismo para que los tests de unidad puedan sobreescribir todas los miembros de una clase independientemente de su ámbito, atributos ( sealed ), etc. aunque seguramente esto traería efectos colaterales de privacidad, ingeniería inversa y otros no deseados.

    Vamos, que a día de hoy hay que ser pragmático, es mejor pocos tests unitarios y bien seleccionados que muchos y poco mantenibles.

  6. Hola a todos.
    Parece que estamos de acuerdo en que crear una librería de Mockers para SharePoint costaría un montón de tiempo y de esfuerzo, pero sería bastante útil. La idea del Bruno de hacer algo conjunto me parece estupenda. El camino a seguir me parece que sería:
    1 – Decidir si utilizar uno de los Mockers existentes, o hacer uno entre nosotros mismos (la primera idea me parece la más razonable).
    1a – Si se decide usar uno de los existentes, cual. Oscar tiene experiencia con Rhino, así que con su ayuda se podría empezar por ese lado a ver qué tan lejos se puede llegar
    1b – Si se va por crear un nuevo Mockeador, decidir por dónde empezar (una herramienta que haga de una forma más o menos automáticamente lo que Dan propone, crear abstracciones de las clases de SharePoint)
    2 – CodePlex sería el sitio indicado, pero un nuevo proyecto se puede tener sin código por máximo un mes, así que es necesario primero empezar por el punto 1 antes de crear el proyecto
    3 – Decidir qué tan lejos se puede/quiere ir. Como Dan dice, es mejor pocos tests buenos que muchos poco mantenibles
    4 – Intentar interesar mas desarrolladores, pues con solamente un par no terminamos nunca
    5 – Se siguen aceptando sugerencias…

  7. Hola Oscar. Lastima… si el proyecto arranca, de pronto un día de estos tengas algo más de tiempo para unirte al asunto. A ver si alguien más se anima, pues el asunto es demasiado grande para mí solo 😎

  8. He comenzado a investigar sobre SharePoint y realmente me parece muy bueno el post. En mi web encontrarás formas de comunicarte conmigo, pues me interesaría aportar mi ayuda en todo lo que esté a mi alcance.
    Nos hablamos…
    Saludos cordiales,

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *