Test Double Testing de Software
Test Double Testing de Software
Tercera Unidad:
TCNICAS DE TESTING
Test Double
En la programacin orientada a objetos, los programadores y desarrolladores emplean una
tcnica llamada automated unit testing para mejorar la calidad del software.
Con frecuencia, el software de la versin final consiste en un complejo conjunto de objetos o
procedimientos que interactan en conjunto para crear el resultado final.
En la automated unit testing, puede ser necesario el uso de objetos o procedimientos que se ven
y se comportan igual que sus homlogos de la liberacin prevista, pero en realidad son versiones
simplificadas que reducen la complejidad y facilitan la prueba.
Una Test Double es un (meta) trmino genrico utilizado para estos objetos o procedimientos.
3.1 Mocking
En la programacin orientada a objetos se llaman objetos simulados (pseudoobjetos, mock
object, objetos de pega) a los objetos que imitan el comportamiento de objetos reales de una
forma controlada.
Se usan para probar a otros objetos en pruebas unitarias que esperan mensajes de una clase en
particular para sus mtodos.
En los test de unidad, los objetos simulados se usan para simular el comportamiento de objetos
complejos cuando es imposible o impracticable usar al objeto real en la prueba.
Resuelve el problema del caso de objetos interdependientes, que para probar el primero debe
ser usado un objeto no probado an, lo que invalida la prueba:
Los objetos simulados son muy simples de construir y devuelven un resultado determinado y de
implementacin directa, independientemente de los complejos procesos o interacciones que el
objeto real pueda tener.
Caractersticas
Los objetos simulados se usan en lugar de objetos reales que tengan algunas de estas
caractersticas:
Viene la gran pregunta Como vamos a poder probarlo si nuestro cdigo necesita utilizar objetos que
todava no estn disponibles?.
Es en este momento donde tiene sentido el uso de objetos mock.
Utilizaremos estos objetos en los proyectos de pruebas de manera que podamos probar nuestro
cdigo simulando el comportamiento de objetos que todava no estn disponibles a travs del uso de
los mocks.
Un mock deber implementar el mismo interfaz del objeto que queremos simular.
En la clase que define la prueba deberemos definir qu mtodos del objeto real queremos que simule
el mock, indicando para cada uno de ellos cual es la respuesta esperada cuando reciba unos
parmetros predeterminados.
Esa respuesta debe ser la misma que esperamos que devuelva el objeto real cuando est disponible.
Al ejecutar la prueba, cuando el cdigo que queremos probar llame a un objeto que todava no est
disponible y que hemos simulado con el mock, esa llamada ser interceptada por el objeto mock
que hayamos definido y este devolver la respuesta que hayamos definido y que se deber
corresponder con la que esperamos que sea devuelta por el objeto real cuando est construido.
La utilizacin de mocks nos permite independizar el desarrollo de unas partes de la solucin de otras.
Podemos desarrollar una parte y verificar que funciona correctamente con independencia del resto
de partes con las que tenga relacin.
De esta manera el responsable de cada parte de cdigo puede centrarse en probar que el cdigo que
est desarrollando funcione correctamente con independencia del estado de otras partes de la
aplicacin con las que tenga relacin.
Al decir esto nos damos cuenta que estamos desacoplando grandes cosas en cosas mas pequeas, lo
cual nos resulta sumamente tiles a la hora de generar los test.
Cuando se hacen las pruebas de esta manera, usted est centrado en uno de los elementos del
software, de ah la necesidad de algn tipo de almacn en nuestro ejemplo.
En los dos estilos de las pruebas que he mostrado anteriormente, el primer caso se utiliza un
objeto de almacn real y el segundo utiliza un almacn simulacro, que por supuesto no es un
objeto de almacn real.
El uso de mock es una manera de no utilizar un almacn real en la prueba, pero hay otras formas
de objetos irreales utilizados en las pruebas de esta manera.
3.2. Stubbing
Un mtodo stub o simplemente stub en el desarrollo de software es un trozo de cdigo utilizado
para sustituir a alguna otra funcionalidad de programacin.
Un stub puede simular el comportamiento del cdigo (por ejemplo, un procedimiento en una
mquina remota) existente o ser un sustituto temporal para el cdigo todava-a-serdesarrollado.
Los stubs son por lo tanto ms til en portabilidad, computacin distribuida, as como el
desarrollo de software en general y pruebas.
se utilizan principalmente en el enfoque de arriba hacia abajo de las pruebas incrementales.
Stubs son programas informticos que actan como reemplazo temporal por un mdulo
llamado y le dan el mismo resultado que el producto real o software.
END IF
END
BEGIN ThermometerRead(Source insideOrOutside)
RETURN 28
END ThermometerRead
Mientras ThermometerRead estara destinado a leer algn dispositivo hardware, esta funcin no
contiene el cdigo necesario.
As ThermometerRead en esencia, simula cualquier proceso, sin embargo, no devuelve ningn
valor legal, permitiendo que el programa principal para este al menos parcialmente a prueba.
Tambin tenga en cuenta que si bien acepta el parmetro de tipo Fuente, que determina si se
necesita dentro o fuera de la temperatura, que no utiliza el valor real transcurrido (argumento
insideOrOutside) por la persona que llama en su lgica.
Un stub es una rutina que en realidad no hace otra cosa que declararse y los parmetros que
acepta y devuelve, es por lo general los valores esperados en uno de los "escenarios felices" de
la llamada.
Los Stubs son comnmente utilizados como marcadores de posicin para la implementacin de
una interfaz conocida, donde la interfaz est finalizado/conocido pero la implementacin an no
se sabe/finalizado.
El trozo contiene suficiente cdigo para permitir que se compile y se enlace con el resto del
programa.
En la nomenclatura RMI, un stub se comunica en el lado del servidor con un esqueleto.
Un fake object es un Double Test con la lgica real (a diferencia de los stubs) y es mucho ms
simplificado o ms barato de alguna manera.
No usamos mock o stubs a una unidad que probamos; ms bien, las dependencias externas de la
unidad son objetos mock o stubs de modo que la salida de los objetos dependientes puede ser
controlada u observada a partir de los test.
El objeto falso sustituye a la funcionalidad del cdigo real que queremos probar.
Los fakes son tambin dependencias, y no se hace mock a travs de subclases (que
generalmente es siempre una mala idea, el uso de la composicin en su lugar).
Los fakes no slo se apag valores de retorno; que utilizan una lgica real.
Concepto: son objetos que reemplazan a otro objeto del sistema con una implementacin
alternativa.
Por ejemplo, el reemplazo de una base de datos en disco por otra en memoria por razones de
desempeo.
Se utilizan ampliamente en el cdigo heredado. Las siguientes son las razones de usar un objeto
falso:
El objeto real no puede ser instanciado, tal como cuando el constructor lee un archivo, realiza una
bsqueda JNDI, y as sucesivamente.
El objeto real tiene mtodos lentos; Por ejemplo, una clase puede tener un mtodo calculate() que
necesita ser probado unitariamente, pero el mtodo calculate() llama a un mtodo load() para
recuperar datos de la base de datos.
El mtodo load () necesita una base de datos real, y se necesita tiempo para recuperar los datos, por lo
que tenemos que pasar por alto el mtodo load () para la prueba unitaria del mtodo calculate().
Introduccin
Todos los programadores saben que deben realizar pruebas a su cdigo, pocos lo hacen de
manera proactiva, la respuesta generalizada al por qu no? es no tengo tiempo.
Este apuro se convierte en un crculo vicioso.
Cuanta ms presin se siente, menos pruebas se realizan.
Cuantas menos pruebas se realizan, menos productivo se es y el cdigo se vuelve menos
estable.
Cuanto menos productivo y preciso se es, ms presin se siente.
Debido a la diversidad de definiciones, convendremos que una buena prueba unitaria tiene las
siguientes caractersticas:
Unitaria, prueba solamente pequeas cantidades de cdigo.
Independiente, no debe depender ni afectar a otras pruebas unitarias.
Prueba mtodos pblicos, de otra forma la prueba sera frgil a cambios en la implementacin y no se
podra utilizar en pruebas de regresin.
Automatizable, la prueba no debera requerir intervencin manual.
Repetible y predecible, no debe incidir el orden y las veces que se repita la prueba, el resultado siempre
debe ser el mismo.
Profesionales, las pruebas deben ser consideradas igual que el cdigo, con la misma profesionalidad,
documentacin, etc.
Respecto al ltimo punto y contrariamente a lo que piensan muchos desarrolladores que el desarrollo
de pruebas unitarias resta tiempo a tareas ms importante las pruebas unitarias por lo general son
simples y rpidas de codificar, el desarrollo de una prueba unitaria no debera tomar ms de cinco
minutos.
Ventajas
Las pruebas unitarias buscan aislar cada parte del programa y mostrar que las partes
individuales son correctas, proporcionando cinco ventajas bsicas:
Fomentan el cambio, las pruebas unitarias facilitan la reestructuracin del cdigo (refactorizacin),
puesto que permiten hacer pruebas sobre los cambios y verificar que las modificaciones no han
introducido errores (regresin).
Simplifican la integracin, permiten llegar a la fase de integracin asegurando que las partes
individuales funcionan correctamente. De esta manera se facilitan las pruebas de integracin.
Documentan el cdigo, las propias pruebas pueden considerarse documentacin, ya que las mismas son
una implementacin de referencia de como utilizar el cdigo.
Separacin de la interfaz y la implementacin, la nica interaccin entre los casos de prueba y las
unidades bajo prueba son las interfaces de estas ltimas, se puede cambiar cualquiera de los dos sin
afectar al otro (ver pruebas mock).
Menos errores y ms fciles de localizar, las pruebas unitarias reducen la cantidad de errores y el
tiempo en localizarlos.
Pueden mejorar el diseo, la utilizacin de prcticas de diseo y desarrollo dirigida por las pruebas (Test
Driven Development o TDD) permite definir el comportamiento esperado en un paso previo a la
codificacin.
Puede ser la forma ms simple de verificar el funcionamiento, en situaciones como el desarrollo de una
API o un componente que brinda servicios del cual no se cuenta an con un cliente para consumirlos.
Adoptar el uso de pruebas unitarias como una disciplina generalizada puede ser un trabajo costoso,
pero no debe ser considerado una desventaja, debe entenderse que esta actividad nos servir para
ahorrar tiempo en el futuro al disminuir la ocurrencia de errores.
La utilizacin de pruebas unitarias permitir mejorar progresivamente la calidad del cdigo en la medida
que los desarrolladores aumenten la calidad de las pruebas y la cobertura del mismo, por ejemplo, "en
MicroGestion durante el ao 2011 se dedicaron 1160 horas a la resolucin de errores en la fase de
desarrollo y en el perodo de garanta, y en 2012 se registraron 710 horas".
Consideraciones
Como en la adopcin de cualquier otra disciplina, la incorporacin de pruebas unitarias no est
exenta de problemas o limitaciones, a continuacin se enumeran algunas consideraciones a tener en
cuenta:
Por estar orientada a la prueba de fragmentos de cdigo aislados, la pruebas unitarias no descubrirn errores
de integracin, problemas de rendimiento y otros problemas que afectan a todo el sistema en su conjunto.
En alguno casos ser complicado anticipar inicialmente cuales son los valores de entradas adecuados para las
pruebas, en esos casos las pruebas debern evolucionar e ir incorporando valores de entrada representativos.
Si la utilizacin de pruebas unitarias no se incorpora como parte de la metodologa de trabajo,
probablemente, el cdigo quedar fuera de sincronismo con los casos de prueba.
Otro desafo es el desarrollo de casos de prueba realistas y tiles. Es necesario crear condiciones iniciales para
que la porcin de aplicacin que est siendo probada funcione como parte completa del sistema al que
pertenece.
Escribir cdigo para un caso de pruebas unitario tiene tantas probabilidades de estar libre de errores como el
mismo cdigo que se est probando.
Por ejemplo, se tiene una clase Calculator que necesita de un DAO (Objeto de Acceso a Datos) para obtener
informacin de la base de datos, este DAO es lo que llamamos el objeto real. Si quisiramos realizar una prueba
de la clase Calculator, deberamos pasarle al objeto una conexin vlida a la base de datos y asegurarnos de que
los datos que necesita existan.
Este proceso de determinar los datos que el objeto necesita e insertarlos en la base requiere de mucho trabajo.
En lugar de esto, se puede proveer una instancia falsa del DAO que slo devuelva lo que necesitamos para la
prueba. Esta clase no va a tomar la informacin de la base de datos, sino que va a ser un mock.
Reemplazar el objeto real hace que probar la clase Calculator sea mucho ms simple. Estrictamente hablando,
dicho objeto que reemplaza al DAO real no sera un mock, sino un stub. Luego hablaremos de esta diferencia.
Este ejemplo puntual de la clase Calculator se puede generalizar diciendo que es una unidad (Calculator)
utilizando un colaborador (DAO).
Unidad Colaborador
Nota: la flecha significa usa.
Cuando reemplazamos al colaborador por un mock (o stub), esto se puede expresar de la siguiente manera:
Unidad Mock
En el contexto de una prueba unitaria se vera de la siguiente manera:
Hay tres tipo de objetos falsos que se pueden usar para reemplazar a los objetos colaborador
para realizar pruebas unitarias: stub, mock y proxy.
Objetos stub
Luego se crea la unidad y se le setea el stub en lugar del colaborador real (2).
Por ltimo se verifica el resultado de la llamada a la unidad (3).
Ejemplo utilizando objetos stub (pseudocdigo)
El TDD (Test Drive development), desarrollo conducido por pruebas, donde la fuerza de nuestros
programas se basa justo en eso, en los test de las clases que vamos generando (De hecho TDD
propone generar los test antes de crear el cdigo de la clase).
Para poder crear un buen conjunto de pruebas unitarias, es necesario que nos centremos
exclusivamente en la clase a testear, simulando el funcionamiento de las capas inferiores.
De esta manera estaremos creando test unitarios potentes que os permitira detectar y
solucionar los errores que tengis o que se cometan durante el futuro del desarrollo de vuestra
aplicacin.
Para esta tarea nos apoyaremos en el uso de mock objects, que no son ms que objetos que
simulan parte del comportamiento de una clase.