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...