Mocking a SharePoint, la historia continua

Hace algo más de un año yo comencé una serie de pequeños artículos en este mismo sitio sobre Pruebas Unitarias para SharePoint (“Mocks, Mocking, Mockers y SharePoint” , “Stubs, Stubbing, Stubbers y SharePoint” y “Morir con las botas puestas o Unit Test con SharePoint”). Después de mucho luchar con el asunto, mi conclusión (temporal) fue que el asunto era entre dificilísimo e imposible.

El tema ha regresado recurrentemente entre tanto. Inclusive hablándolo con Carlos Segura alguna vez, el salió con una forma de hacer Pruebas Unitarias (http://www.ideseg.com/BeginnersGuideToTDWebPartDevelopment.aspx) que en realidad nunca me ha gustado por complicada y “poco elegante” y por no eliminar la dependencia con SharePoint.

De lo que se trata en resumen es de como realizar Pruebas Unitarias para código de SharePoint. El problema es bastante sencillo: es necesario eliminar de una u otra forma las dependencias del código con respecto al API de SharePoint para poder repetir las pruebas una y otra vez sin depender del estado actual del Portal; inclusive, si es posible, sin depender DE NINGUNA MANERA de SharePoint. El método de Carlos se basa en la creación de plantillas para Sitios o Listas que se cargan dinámicamente al principio de la Prueba Unitaria y se destruyen al final. Esto garantiza que se mantenga un estado constante en SharePoint, pero, fuera de ser engorroso y (extremadamente) lento, solo permite probar algunas cosas del API de SharePoint (todo lo que tenga relación con Sitios y Listas), pero no permite hacer pruebas de la parte administrativa, por ejemplo. Y siempre es necesario tener una instalación de SharePoint detrás, con todas las subordinaciones necesarias de URL, configuración de usuarios, etc.

Para eliminar realmente las dependencias es necesario usar Mockers o Stubbers (los artículos mencionados al principio dan una pequeña idea de que son estas dos cosas). Hace un par de semanas, TypeMock, uno de los frameworks para Mockers, ha salido al mercado con una nueva versión que permite mucho más de lo que era posible de hacer anteriormente. Desafortunadamente la herramienta (http://www.typemock.com) no es gratis, pero es posible descargar una versión de prueba de 30 días. El problema para mockear a SharePoint es que muchas (demasiadas) de sus clases son selladas y/o no tienen constructores públicos, por lo que para poder utilizar Mockers “tradicionales” es necesario crear primero Interfaces, y luego mockear la clase indirectamente. Como se podrán imaginar, esto es trabajo imposible de hacer, teniendo en cuenta que el Modelo de Objetos de SharePoint es tan increíblemente extendido.

Pues bien, la nueva versión de TypeMock permite trabajar también con este tipo de clases, lo que facilita el asunto considerablemente. TypeMock viene con diferente tipos de sintaxis, una de las cuales, “Natural Mock” es bastante sencilla de utilizar. El siguiente es un ejemplo idiota, pero que sirven para ver cómo funciona el asunto. Queremos crear una Prueba Unitaria del siguiente método, que simplemente devuelve el URL de la página maestra de un sitio:

 

public string MethodOne(string SiteUrl)

{

    String strReturn = String.Empty;

    SPSite mySite = null;

    SPWeb myWeb = null;

    try

    {   

        mySite = new SPSite(SiteUrl);

        myWeb = mySite.OpenWeb();

        strReturn = myWeb.MasterUrl;

    }

    catch (System.Exception ex)

    {

        strReturn = ex.ToString();

    }

    finally

    {

        if (myWeb != null) myWeb.Dispose();

        if (mySite != null) mySite.Dispose();

    }

    return strReturn;

}

 

Si queremos hacer Pruebas Unitarias sobre este método, necesitamos eliminar la dependencia del SPSite y del SPWeb (no queremos tener que tener una instalación de SharePoint detrás, que probablemente va a cambiar constantemente, por lo que nunca sabremos con certeza que es lo que nos va a devolver). Nuestro método de prueba usando TypeMock y la infraestructura por defecto de Visual Studio sería más o menos:

 

[TestMethod()]

public void MethodOneTest()

{

    using (RecordExpectations recorder = RecorderManager.StartRecording())

    {

        SPSite mySiteMocked = new SPSite(“”);

        SPWeb myWebMocked = RecorderManager.CreateMockedObject<SPWeb>();

        recorder.ExpectAndReturn(mySiteMocked.OpenWeb(), myWebMocked);

        recorder.ExpectAndReturn(myWebMocked.MasterUrl, “abcd.master”).RepeatAlways();

    }

    MisObjetos target = new MisObjetos();

    string SiteUrl = string.Empty;

    string expected = “abcd.master”;

    string actual;

    actual = target.MethodOne(myListMocked);

    Assert.AreEqual(expected, actual);

    //Assert.Inconclusive(“Verify the correctness of this test method.”);

}

 

La parte al principio (alrededor del “using”) es en donde creamos nuestro “Mock”, es decir, allí “falsificamos” lo que SharePoint deberá hacer por su cuenta cuando el código funcione realmente. En el primer renglón se crea una instancia de SPSite; note que no es necesario entregarle un URL para crearla, pues el objeto será de todas formas falso, así que no vale la pena crear algo “real”. El segundo renglón crea un objeto SPWeb utilizando una sintaxis especial para la creación de objetos que serán modificados posteriormente (el objeto SPSite es utilizado solamente como referencia, pero no será modificado). La tercera línea le indica al mockeador que el objeto SPWeb creado corresponde al objeto que puede encontrar en el objeto SPSite.OpenWeb. Finalmente la cuarta línea simplemente le asigna un valor a una propiedad del objeto SPWeb (el nombre de su Pagina Maestra).

Las líneas siguientes son generadas automáticamente por Visual Studio, y lo único que es necesario de modificar es el valor esperado. Lo que ocurre al ejecutar la Prueba Unitaria es muy sencillo: el framework de TypeMock le “hace creer” al código que tiene un objeto SPSite y otro SPWeb y ejecuta el método con esos objetos. Esto es sencillo de explicar de esta manera, pero “por debajo de la mesa” ocurren muchas otras cosas que no tienen importancia para el caso dado.

Pues bien, estas son las conclusiones:

Las buenas noticias: Este nuevo framework hace posible crear Pruebas Unitarias para SharePoint. Punto.

Las malas noticias 01: Se ha dado cuenta que para tres renglones de código “de trabajo” se necesitan cuatro líneas de código “de prueba”? Y un ejemplo más sencillo simplemente no me he podido inventar. La realidad es que es necesario mockear cada uno de los objetos utilizados, lo que rápidamente conlleva a que el método de prueba sea más largo (y hasta complicado) que el método a probar.

Las malas noticias 02: Probablemente por mí propia ineptitud, estoy teniendo enormes problemas al intentar mockear colecciones de objetos. Me he dado cuenta que los problemas ocurren porque necesito implementar una Interface IEnumerator que parece que SharePoint utiliza de uno u otra rara manera… en cualquier caso, si intento mockear un SPListCollection, por ejemplo, siempre termino en el basurero de los errores terminales…

Coletilla: Probablemente seguiré escribiendo sobre el asunto por un par de artículos más. Si a alguien le da la rara idea de experimentar con este (apasionante) asunto, por favor, envíenme un E-mail, y de pronto entre todos encontramos soluciones a los problemas que se ven venir…

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

Un comentario en “Mocking a SharePoint, la historia continua”

  1. Me consta que desde el principio, que el sistema de pruebas que plantee (el mismo que se ha usado testeando bases de datos por mucho tiempo) y que uso actualmente no te gusto.
    La cosa es que va para un año el tiempo que llevo usando este sistema, creo que el mes pasado mis pruebas hacían una cobertura de algo más de 100.000 líneas de código [yo fui el primer sorprendido]. Las pruebas es una cuestión de actitud, como muchas otras cosas en la vida.
    Para mí, lo de no me valen porque me cuestan demasiado no vale. Si quieres hacerlas, hazlas.
    También te diré que viendo lo que hace TypeMock mañana mismo probaré.
    Sin acritud.

Deja un comentario

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