¿Los test de construcción son desechables?

Sigo con mi proyecto personal de UniversalSync y, respondiendo a las notificaciones de publicación en twiter, he recibido el primer feedback de compañeros a los que respeto mucho, que me han señalado las mejoras y dudas sobre el código que he mostrado en el artículo anterior.

Por ello de este artículo. Con un poco sentido de “dar explicaciones”, pero sobre todo para compartir mis pensamientos según sigo construyendo y picando.

 TDD y los test desechables

No hago TDD puro. No hago siempre el test primero , sino que primero codifico la firma del método que quiero construir y luego arranco el ciclo rojo, verde, refactoriza.

Pero si es cierto que, para mí, lo más potente del TDD no es tanto que me obliga a KISS, si no que me permite probar las cosas de forma rápida y sencilla. Aportando, a la vez, una red de seguridad sobre la que puedo hacer todas las refactorizaciones que se me ocurran.

Lo malo, y es importante, es que voy dejando un rastro de test obsoletos que tuvieron sentido solo y exclusivamente para construir un componente que ya no es correcto probar de esa forma.

Me explico:

Para conectarme con un Azure Storage Blob, lo primero que debo hacer es crear una referencia a su Container. Por lo cual lo primero que hago (luego de crear el método) es construir un test que compruebe que lo estoy haciendo bien:

    [TestClass()]
    public class BlobContanierTests
    {
        [TestMethod()]
        public void CreateContainer()
        {
            var blobcontainer = new BlobContanier();

            CloudBlobContainer blob = blobcontainer.Create();

            Assert.IsNotNull(blob);
        }
    }

Fíjate en dos cosas:

  • El Assert está pensado para comprobar que ninguna de las operaciones necesarias para recuperar la referencia genera una excepción (si falla no devuelve nulo, devuelve un “casque”)
  • No uso var en el tipo esperado de la variable blob, ya que le estoy diciendo desde el test el tipo de resultado que estoy esperando (otra forma de probar).

El código, obviamente, es más simple que el chupete de un niño (ya he corregido lo de tener las referencias a fuego y ahora vá por claves en el app.config):

    public class BlobContanier
    {
        public CloudBlobContainer Create(string containerReference = "")
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(CloudConfigurationManager.GetSetting("ContainerReference"));
            container.CreateIfNotExists();
            return container;
        }
    }

Pero lo importante es que en el momento que este test se pone a verde… ya no es necesario.

Un test de construcción no siempre es un test unitario

Esta manera de probar una cadena de conexión no solamente no es buena, si no que es erronea. Realmente estoy probando que la librería de Azure Storage funciona correctamente, y probar algo que así es perder el tiempo. Puedo dar por supuesto que funciona.Y si falla, debo tratar la excepción que lance como lo que es: algo excepcional.

Por lo cual los test de pruebas que utilicé para guiar la construcción de los métodos Get, Put y Delete, tampoco son necesarios ya. Ni me aportan valor, ahora mismo. Ya que lo que deberían poner a prueba y asegurar es la lógica de su uso.

Y es importante remarcar el “ahora mismo”, porque pensé seguir el consejo de borrarlos y dejar solo el backup del histórico del repositorio de código. Pero otro compañero me ha recordado que el día de mañana, si quiero migrar el código a NET. Core, estos test volverán a tener mucho valor y me valdrán como red de seguridad y cimientos para refactorizar y recodificar.

En resúmen, debo tener cuidado al mezclar los test de diseño/construcción, con los test unitarios de mi aplicación. Los primeros son imprescindibles para construir siguiendo las premisas de TDD, pero tengo que meditar cuales son los que me aportan valor y fortaleza a mi código una vez construida la pieza del software.

Y no dudar en almacenar los que no tenga ya sentido porque solo me van a dar una falsa sensación de seguridad, ocultando los verdaderos riesgos de fallos.

Espero que sea de utilidad, no dudes en opinar en los comentarios y nos vemos en el siguiente artículo

 

Anuncios

6 comentarios en “¿Los test de construcción son desechables?

  1. Me está gustando mucho esta serie de posts, no porque me apasione el mundo de Azure Storage Blob, sino por la apertura con la que lo estás haciendo. Enhorabuena.

    Sobre el tema de los tests, lo que tú llamas tests de construcción, que a veces he visto llamar “tests exploratorios” o cosas similares, yo no los consideraría tests como tales. Sirven para comprobar cómo funciona algo y aprender a manejarlo, pero que lo hayas implementado como tests de MSTest es algo anecdótico, podrías haberlo hecho con una aplicación de consola y te hubiera servido para lo mismo: aprender a manejar el cliente de ASB.

    Mantenerlos o no, es tan sencillo como preguntarte si te sirven o no. Personalmente no doy mucha importancia a nombrar los tests como unitarios, integración, etc., y seguir a rajatabla la “pirámide de los tests” y otras “buenas prácticas”, al final he acabado por centrarme únicamente en si me aportan valor o no me lo aportan. En base a eso, decido si quedármelos.

    En este caso concreto, una vez que ya sabes cómo funciona ASB, probablemente no tenga sentido mantenerlos, aunque si fuese una aplicación muy crítica, tener unos tests de humo un poco más complicados puede ayudarte a detectar cambios en las librerías/servicios externos.

    Aun así, este tipo de tests suele ser costoso de escribir, mantener y ejecutar, por lo que tendrías que analizar bien si realmente te compensan. Todo esto, claro está, viéndolo desde un punto de vista “profesional”. En una aplicación que se hace para aprender, tiene todo el sentido del mundo invertir tiempo en experimentar con cosas “no rentables” por el mero hecho de saber cómo se hacen.

    Me gusta

  2. Creo que lo importante es tener siempre claro cuál es el objetivo cada vez que escribimos un test. El motivo que nos ha llevado a hacer el test debería ser el que determinase si el test se queda o es borrado.

    Si el objetivo es hacer un spike para aprender mejor a utilizar una tecnología, una vez que se ha cumplido el objetivo, lo más probable es que esos tests sean innecesarios. Es más, tal como comenta Juanma, no deja de ser un mecanismo para poder ejecutar tu código. Que sea un test es algo circunstancial. Podrías haber utilizado el REPL o un proyecto de línea de comandos y el objetivo sería el mismo.

    No obstante, estas son algunas motivaciones que nos llevarían a no querer borrar los tests parecidos, pero que tienen objetivos distintos:

    Monitorización y diagnóstico.- Cuando hablamos de servicios externos, hay ocasiones en las que se hacer un test para verificar que el servicio funciona. Así tienes un test que te va a avisar cada vez que el funcionamiento de Azure Blob Storage no es el que esperas, tienes una porción de código muy específica que te permite tirar de hilo con mucha facilidad para diagnosticar el problema.

    Compatibilidad.- Comentas en tu post que probar que la librería de Azure Storage funciona correctamente es perder el tiempo pero, ojo! que podría no serlo. No sería la primera vez que un proveedor de servicios actualiza un servicio y requiere a su vez una actualización de la librería que consume ese servicio porque se han pasado el tema de la retrocompatibilidad, el open/close principle, etc. por el forro.

    Tests de integración.- Si estamos accediendo a un servicio como ABS, lo habitual será crear algún tipo de abstracción, lo que también daría sentido a la creación de una batería de tests que verifiquen que la implementación de tu abstracción es la correcta. Este tipo de tests serían precisamente los que te permitirían verificar si tu código funciona en .Net Core.

    Por supuesto, en cada caso, como el objetivo es distinto, posiblemente el propio test tenga una estructura y se ejecute en momentos distintos del ciclo de desarrollo.

    Me gusta

  3. Muy buenas,

    yo este tipo de tests directamente no los escribiría. Como dice Juanma, seguramente una aplicación de consola es más adecuada. O ahora que hay un REPL para C#, es un buen sitio para probar esas cosas.

    Otra cosa es que quieras hacer tests de integración con un servicio para ver si han cambiado la api, continua vivo, etc.

    Lo que tu comentas de construcción, a mi a veces me pasa que empiezo una clase haciendo un assert que se está llamando a un colaborador. Ese test tiene un sentido al principio, pero lo pierde rápido, con lo que lo acabo borrando.

    Salut!

    Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s