Documentos de Académico
Documentos de Profesional
Documentos de Cultura
UniTest
Las pruebas unitarias o unit testing son una forma de comprobar que un fragmento
de código funciona correctamente. Es uno de los procedimientos que se llevan a
cabo dentro de una metodología ágil de trabajo.
Video de inmersión
Glosario
Video de habilidades
Referencias
Lección 1 de 6
Video de inmersión
Verify to continue
We detected a high number of errors from your
connection. To continue, please confirm that
you’re a human (and not a spambot).
C O NT I NU A R
Lección 2 de 6
Cuando hablamos de programas grandes donde intervienen varios desarrolladores que trabajan
simultáneamente, el proceso de pruebas cobra especial importancia si consideramos que:
Cuando una sola persona al hacer un programa más o menos pequeño, normalmente,
puede ir modificando su código poco a poco, compilar de vez en cuando, ejecutarlo y
ver si lo que está haciendo funciona. El proceso de probar a mano puede llevarle un
tiempo razonable y el programa puede, al final, quedar perfectamente hecho.
Al ser un programa grande, las pruebas manuales deben ser frecuentes, para comprobar
que según pasa el tiempo, lo que estaba funcionando, sigue funcionando, además de
comprobar que lo que acabamos de hacer también funciona. Pero al mismo tiempo, al
ser el programa más grande, esas pruebas manuales llevan cada vez más tiempo, ya
que cada vez hay más cosas que probar.
Sería maravilloso si hubiera algo que probara nuestro programa de forma automática y
con frecuencia. Si cada vez que hacemos cambios o añadimos código le decimos a
ese algo que prueba nuestro programa y nos despreocupamos del tema, nos
ahorraríamos mucho tiempo de prueba.
Afortunadamente, existe ese algo. Podemos hacer un programa que se encargue de
probar nuestro programa. Ese programa de pruebas debería ser fácil de lanzar,
deberíamos lanzarlo con frecuencia, no debería requerir ninguna intervención por
nuestra parte y no debería darnos unos resultados que tengamos que analizar.
Únicamente debemos lanzarlo y él solo debe decirnos: "Todas las pruebas han ido
bien". O, si no hemos tenido suerte (si tal cosa existe): "Han fallado estas pruebas en
estos sitios".
Obviamente, hacer estos programas de prueba es más trabajo, pero cuando más
grande y complejo es el proyecto en el que estamos involucrados, más tiempo vamos a
ahorrar a la larga. Las ventajas de tener unos buenos programas de prueba son:
1. Al ser la prueba automática, nos dará menos pereza lanzarla con frecuencia. De hecho,
lo ideal es hacer un trozo de código y pasar las pruebas. Si hemos fastidiado algo,
sabremos que el trozo de código que acabamos de tocar es el que ha introducido el
fallo. Si la prueba es larga y manual, seguramente probaremos con menos frecuencia.
Si algo se estropea, quizás tengamos que buscar el fallo en el código que hemos hecho
durante toda la semana.
2. Tener las pruebas automáticas nos quita el miedo a tocar el código que ya está
funcionando. A veces vemos código que está funcionando, pero que no está todo lo
bien hecho que debiera. Otras veces, tenemos que arreglar un poco ese código para
poder reutilizarlo en una nueva funcionalidad que queremos dar a nuestro.
3. Si no tenemos una forma fácil de ver que ese código sigue funcionando después de
tocarlo, igual no nos decidimos a tocarlo.
4. Una prueba automática que falla nos da más información que una prueba manual que
detecta un fallo. Si una prueba automática falla, nos dice exactamente qué método del
código no hace lo que se esperaba de él. Si una prueba manual encuentra un fallo, solo
sabemos que algo en cualquier parte del código no está bien.
Las pruebas automáticas ayudan mucho, pero tampoco garantizan nada al 100%.
Nunca nos quitaremos del todo la necesidad de hacer pruebas manuales, pero incluso
haciendo pruebas manuales, algunos errores colapsarán y saldrán más adelante... o
nunca. Las pruebas automáticas son simplemente una primera criba que nos ahorrará
tiempo al detectar automáticamente un porcentaje alto de los errores en el código.
Resumiendo, los test (pruebas) automáticos son programas que se encargan de probar nuestro
programa. Estos programas de pruebas deberían tener la particularidad de ser fácil de lanzar. Además,
deberían prescindir de la intervención del desarrollador y darnos resultados que no requieran de análisis
posterior.
Nos sirven para evitar que se comentan errores en el código, ya que nos indicarán en qué funcionalidad
no pasó la prueba. Nos dan más información al detectar un fallo. Nos permiten generar una frecuencia
constante en las pruebas, lo que nos da más confianza en el desarrollo.
Es la que proporciona una visión arquitectónica completa del sistema de automatización de pruebas,
mediante una serie de vistas arquitectónicas distintas para representar diferentes aspectos del sistema.
Sirve como medio para gestionar y comunicar las características fundamentales y las funciones del
sistema de software de automatización de pruebas. Ofrece una perspectiva dominante para el software
de automatización de pruebas que habilita la ejecución del sistema necesario respecto a ciertos
aspectos claves: mantenimiento, capacidad de ampliación, fiabilidad, concurrencia, distribución,
seguridad y recuperación.
Figura 1. UI test architecture
Las tareas de automatización de pruebas están cada vez más presentes en el mercado. Hay disponibles
gran cantidad de herramientas de automatización. Sin embargo, es poco común que una única
herramienta sea capaz de automatizar todas las tareas de prueba.
En general, la gran mayoría de estas herramientas se enfocan en una tarea o en un grupo de tareas
específicas. Hay otras, en cambio, que se encargan de un aspecto específico de una tarea.
Pruebas funcionales
–
Las pruebas funcionales se definen teniendo como fuente los requisitos del sistema,
estas pruebas validan y verifican que el producto cumple con lo especificado y hace lo
que debe y cómo lo tiene que hacer dando también una idea del grado de calidad del
software. (Tester House, 2019).
Pruebas unitarias.
Pruebas de aceptación.
Pruebas de integración.
Pruebas de regresión.
Pruebas de humo.
Pruebas de cordura.
Pruebas de componentes.
Pruebas unitarias
–
Son las que aseguran que cada célula del código desarrollado en un componente brinde los resultados
adecuados. En estas pruebas los desarrolladores observan la interfaz y la especificación de un
componente, proporcionando la documentación del desarrollo del código.
Las pruebas unitarias admiten pruebas funcionales al ejercer el código que es más probable que se
rompa. Por ello, si usamos pruebas funcionales sin pruebas unitarias, podemos experimentar algunas
dificultades para diagnosticar pruebas fallidas. Así que hay que tenerlas muy presentes.
Pruebas de componentes
–
Las pruebas de componentes se ejecutan de forma independiente para comprobar que el resultado sea
el requerido. Su objetivo es verificar las funcionalidades o usabilidades de los componentes, aunque no
solo se limite a eso.
Para ilustrar mejor, un ejemplo de esta prueba puede ser cualquier elemento que tenga entrada y deba
generar alguna salida. Puede ser el módulo de código, página web, pantallas e incluso un sistema
dentro de un sistema más grande. Aquí, algunos usos de los componentes que podemos probar:
Cuando ya hemos seguido e implementado las pruebas que requerimos para nuestro
producto, hacemos las pruebas de aceptación. Estas hacen parte de la última fase de
este proceso de testing. Aquí los usuarios reales del software lo usan para verificar
que cumpla con las tareas requeridas en un ambiente “real”. En ocasiones se realiza
cuando se hace la entrega del producto como punto de control final entre todos los
tipos de pruebas funcionales.
Pruebas de integración
Es uno de los tipos de prueba funcional más común y se realiza de forma
automatizada. Se realizan para probar componentes individuales con el objetivo de
verificar cómo los módulos, que trabajan de forma individual, funcionan cuando están
integrados.
Pruebas de regresión
El objetivo de las pruebas de regresión es encontrar errores que puedan haber sido
introducidos accidentalmente en la compilación existente y así garantizar que los
errores eliminados continúen así.
Pruebas de humo
Es una de las pruebas funcionales más importantes y debería ser la primera que se
realice en una nueva compilación. La prueba de humo es común y aunque a veces no
se tiene claro su concepto. No se trata de realizar pruebas exhaustivas, sino de
verificar que la funcionalidad crítica del sistema realmente funciona bien.
Prueba de cordura
Si tienes una compilación con modificaciones menores, en vez de ejecutar las pruebas
de regresión, realizamos este tipo de prueba.
Con ella podemos determinar que las modificaciones realmente hayan solucionado los
problemas. Y que dichas correcciones no hayan generado ningún problema. Usualmente
estas pruebas son subpruebas de la de “regresión”, ya que están relacionadas con los
cambios realizados en el producto. No confundas las pruebas de humo con las de
cordura por una simple razón.
Las pruebas de software no funcionales son las que se hacen desde una perspectiva
totalmente diferente a las pruebas automatizadas. Este tipo de plan de pruebas son un
medio de control de calidad, que se realiza en aplicaciones de software para asegurarse
de que todo funciona bien y poder saber en qué circunstancias podrían fallar.
Las pruebas no funcionales de software nos permiten conocer qué riesgos corre
el producto y nos dicen si tiene un mal desempeño o un bajo rendimiento en los
entornos de producción. En ese sentido, las pruebas de software no funcionales se
hacen con el fin de obtener información. Permiten explicar lo que soporta el producto y
si cumple con las expectativas de los clientes. Las pruebas no funcionales son:
Pruebas de carga.
Pruebas de estrés.
Pruebas de rendimiento.
Pruebas de carga
Pruebas de rendimiento
Pruebas de estrés
Ejemplo: encontrar la cantidad de usuarios que soporta de manera simultánea hasta que
la aplicación deja de responder (cuelgue o time out), haciéndolo de forma correcta
según todas las peticiones. (Soto Morales, 2021, https://n9.cl/vm3kz).
También hay que tener en cuenta las llamadas pruebas de caja blanca y pruebas de caja negra. En
realidad, estas no son tipos de pruebas, sino que se definen como técnicas de pruebas de software.
Al evaluar las diferentes herramientas para la automatización de pruebas, es importante conocer el tipo
de técnica que compone la herramienta. En ese sentido, hay que conocer sus limitaciones y el tipo de
tareas a las que se dirige y que puede automatizar. Las herramientas de prueba suelen evaluarse y
adquirirse en función de:
Función.
Función
Las herramientas de prueba se pueden categorizar según las funciones que realicen.
Algunas designaciones de funciones típicas para herramientas son:
Herramientas de adquisición de datos que adquieren datos para utilizar en las tareas
de prueba. Los datos se pueden adquirir mediante la conversión, la extracción, la
transformación o la captura de datos existentes, o mediante la generación de guiones
de uso o especificaciones suplementarias.
Las herramientas de prueba suelen caracterizarse como cajas blancas o cajas negras
en función de cómo se utilicen, o la tecnología y los conocimientos necesarios para
utilizarlas.
Las herramientas de caja blanca dependen del conocimiento del código, los modelos
de diseño y otro material de origen para implementar y ejecutar las pruebas.
Las herramientas de caja negra dependen de los guiones de uso o la descripción
funcional del destino de la prueba.
Especialización
Las herramientas del comparador comparan los resultados de la prueba con los
resultados de referencia e identifican las diferencias. Los comparadores se diferencian
en su especificación para formatos de datos particulares. Por ejemplo, pueden basarse
en píxeles para comparar imágenes de mapa de bits o en objetos para comparar las
propiedades o los datos del objeto.
El testing (proceso de prueba) es una poderosa estrategia para bajar los costos y optimizar los tiempos.
Por otra parte, permite ejecutar mayor cantidad de pruebas, sin necesidad de
incrementar el número de personas dedicadas a testear. Esto hace que el equipo de
trabajo sea mucho más eficiente y productivo, haciendo rentable la ejecución de
pruebas de software.
VERSATILIDAD. Da solución a un problema que sufren muchas empresas que cuentan
con sistemas “Legacy” (heredados, antiguos), para los cuales es tan difícil encontrar
técnicos especializados para su mantenimiento como técnicos que puedan ocupar su
tiempo y conocimiento en probar las modificaciones que se implementan.
ANÁLISIS. Las corridas programadas de los test automatizados generan reportes que
permiten conocer el tiempo completo de la ejecución de la totalidad de los casos, el
tiempo de ejecución para cada caso, el resultado obtenido luego de cada prueba y, de
producirse, el error que haya provocado la falla de alguna de las pruebas, lo que
permitirá a posteriori modificar el código necesario para que el sistema continúe su
funcionamiento tal cual lo esperado. (Lezcano, 2020, https://n9.cl/txtwo).
Pruebas repetibles.
El trabajo que implica desarrollar una prueba automatizada es recompensado por la gran
cantidad de veces que será ejecutada. En los casos donde la prueba requiere de poco
mantenimiento, porque el software es estable, el beneficio es la practicidad, ya que la
prueba se realiza sin esfuerzo alguno. Para test regresivos, las pruebas automatizadas
se podrán ejecutar una y otra vez a medida que el software evolucione, asegurando
consistencia y que todo lo que funcionaba en la versión anterior, seguirá funcionando en
la nueva. (Software Testing Bureau, 2021, https://n9.cl/6pxw).
En conclusión, el testing automatizado es una práctica que hace viable la producción de una solución
con pruebas eficientes. Además, permite concentrar los esfuerzos del equipo de testing en las pruebas
más críticas, haciendo un excelente complemento con las pruebas automatizadas.
Una revisión efectiva del código evita que los errores y fallos se introduzcan en el proyecto, mejorando la
calidad del código en una fase temprana del proceso de desarrollo del software.
El objetivo principal del proceso de revisión del código es evaluar cualquier nuevo
código para detectar errores, fallos y normas de calidad establecidas por la
organización. El proceso de revisión del código no debe consistir solo en una
retroalimentación unilateral. Por lo tanto, un beneficio intangible del proceso de revisión
de códigos es la mejora de las aptitudes de codificación del equipo colectivo.
1 Review Board.
2 Crucible.
3 GitHub.
4 Phabricator.
5 Collaborator.
6 CodeScene.
7 Visual Expert.
8 Gerrit.
9 Rhodecode.
Veracode.
10
11 Reviewable.
La primera versión de Review Board salió hace más de una década, pero todavía está
en desarrollo activo. Por lo tanto, la comunidad de Review Board ha crecido a lo largo
de los años y es probable que encuentre soporte si tiene algún problema al usar la
herramienta.
El Review Board es una simple herramienta para revisiones de código, que puedes
alojar en tu servidor. Deberías probarla si no deseas alojar tu código en un sitio web
público. (Daityari, 2020, https://n9.cl/403aa).
Figura 4. Crucible
Figura 5. GitHub
Figura 6. Phabricator
Fuente: Daityari, 2020, https://n9.cl/403aa
Figura 7. CodeScene
Es una herramienta de revisión de código que va más allá del análisis de código
estático tradicional. Realiza análisis de código de comportamiento incluyendo una
dimensión temporal para analizar la evolución de su código base de código. CodeScene
está disponible en dos formas: una solución basada en la nube y una solución en las
instalaciones.
“Los planes de CodeScene basados en la nube empiezan gratis para los repositorios
públicos alojados en GitHub, pero luego se deberá abonar una suscripción”.
CodeScene procesa su historial de control de versiones para proporcionar
visualizaciones del código. Además, aplica algoritmos de aprendizaje de máquina para
identificar patrones sociales y riesgos ocultos en el código.
A través del historial de control de versiones, CodeScene perfila a cada miembro del
equipo para trazar su base de conocimientos y crear dependencias entre los equipos.
También introduce el concepto de puntos calientes en su repositorio, identificando los
archivos que experimentan mayor actividad de desarrollo. Estos hotspots (puntos
calientes) requieren la mayor atención en el futuro. (Daityari, 2020, https://n9.cl/403aa).
Figura 8. CodeScene
Además de una revisión de código tradicional, Visual Expert analiza cada cambio en su
código para prever cualquier problema de rendimiento debido a los cambios. La
herramienta puede generar automáticamente una documentación completa de su
aplicación a partir del código también.
Si estás usando PowerBuilder, SQL Server, u Oracle PL/SQL y deseas una herramienta
de revisión de código especializada para tus necesidades, deberías probar Visual
Expert. (Daityari, 2020, https://n9.cl/403aa).
Figura 10. Gerrit
Análisis estático: una herramienta que permite a los desarrolladores identificar y corregir
los fallos de seguridad en su código.
Además, GitHub tiene límites de línea relativamente pequeños para mostrar las
diferencias de los archivos.
Si buscas una herramienta que sea coherente con GitHub, pero quieres más
características que peticiones de extracción, Reviewable debería ser tu herramienta de
trabajo. (Daityari, 2020, https://n9.cl/403aa).
Si utilizas Subversion, el plugin (complemento) “Peer Review for Trac” (revisión por
pares para la vista) proporciona una opción gratuita y de código abierto para realizar
revisiones de código en tus proyectos. El plugin de revisión por pares se integra en el
proyecto de código abierto Trac, que es un wiki y un sistema de seguimiento de
problemas para proyectos de desarrollo.
Trac integra el wiki y el rastreador de problemas con sus revisiones para proporcionar
una solución integral. Mientras que la funcionalidad básica de comparación de cambios
y conversación está disponible, el plugin te permite diseñar flujos de trabajos
personalizados para tus proyectos.
Por ejemplo, se podrían decidir las tareas a realizar en los activadores, como la
presentación de un cambio o la aprobación en una revisión de código. También puedes
crear informes personalizados sobre tus proyectos. (Daityari, 2020, https://n9.cl/403aa).
C O NT I NU A R
Lección 3 de 6
En pocas palabras y lo más usual sería revisar el flujo correcto de los métodos de
nuestras clases a través de pruebas que vamos a definir para corroborar que el método
se comporte de la manera esperada antes distintos escenarios. Asimismo, si más
adelante se modifica nuestro método, se tendrá que corroborar los cambios a través de
las pruebas unitarias para que se acepte la modificación. (Rodríguez Patiño, 2020,
https://n9.cl/go830).
La idea es escribir casos de prueba para cada función no trivial o método en el módulo, de forma que
cada caso sea independiente del resto. Luego, con las pruebas de integración, se podrá asegurar el
correcto funcionamiento del sistema o subsistema en cuestión.
Características
Para que una prueba unitaria posea la “calidad suficiente” debe ser:
Automatizable.
Completa.
Repetible.
Independiente.
Profesional.
Ventajas
1. Proporciona un trabajo ágil. Como procedimiento ágil que es, te permite poder detectar
los errores a tiempo, de forma que puedas reescribir el código o corregir errores sin
necesidad de tener que volver al principio y rehacer el trabajo. Puesto que las pequeñas
se van haciendo periódicamente y en pequeños packs. Disminuyendo el tiempo y el
coste.
2. Calidad del código. Al realizar pruebas continuamente y detectar los errores, cuando el
código está terminado, es un código limpio y de calidad.
3. Detectar errores. A diferencia de otros procesos, los test unitarios nos permiten detectar
los errores rápidamente, analizamos el código por partes, haciendo pequeñas pruebas y
de manera periódica, además, las pruebas se pueden realizar las veces que hagan falta
hasta obtener el resultado óptimo.
4. Facilita los cambios y favorece la integración. Los test unitarios nos permiten modificar
partes del código sin afectar al conjunto, simplemente para poder solucionar bugs que
nos encontramos por el camino. Los test unitarios, al estar desglosados en bloques
individuales permiten la integración de nuevas aportaciones para hacer un código más
complejo o actualizarlo en función de lo que el cliente demande.
7. El diseño. Si primero se crean los test, es mucho más fácil saber con anterioridad cómo
debemos enfocar el diseño y ver qué necesidades debemos cumplir. Testeando una
pieza del código, también puedes saber que requisitos debe cumplir, y por eso mismo te
será mucho más fácil llegar a una cohesión entre el código y el diseño.
8. Reduce el coste. Partiendo de la base de que los errores se detectan a tiempo, lo cual
implica tener que escribir menos código, poder diseñar a la vez que se crea y optimizar
los tiempos de entrega, vemos una clara relación con una reducción económica.
(Apiumhub, 2018, https://n9.cl/bzlxt).
Cada caso de prueba debe implementar las siguientes tres “A” para que se puedan
ejecutar con éxito.
Arrange (organiza): organiza tu prueba para que se pueda comenzar con las pruebas
ya sea creando los parámetros u objetos mock (objetos ficticios que facilitan las
pruebas) para tu método o función.
Limitaciones
Las pruebas unitarias no descubrirán todos los errores del código como, por ejemplo, de integración,
problemas de rendimiento y todo aquello que afecte al sistema en conjunto. Son efectivas si se utilizan
en conjunto con otras pruebas de software.
Es necesario saber que las pruebas unitarias por sí solas, no son perfectas, puesto que
comprueban el código en pequeños grupos, pero no la integración total del mismo. Para
ver si hay errores de integración es necesario realizar otro tipo de pruebas de software
conjuntas y de esta manera comprobar la efectividad total del código. (Apiumhub, 2018,
https://n9.cl/bzlxt).
Preguntas de reflexión
¿Cuáles son los escenarios más favorables para planear y ejecutar test automatizados?
Considerando que hoy en día las grandes empresas están migrando sus aplicaciones al
entorno web, ¿qué tipo de estrategia utilizarías para monitorear los desarrollos con respecto
a los test funcionales?
Desde el aspecto potestad, es decir, mirando los test según a quién le pertenecen,
distinguimos entre test escritos por desarrolladores y test escritos por el dueño del
producto. Recordemos que el dueño del producto es el analista de negocio o bien el
propio cliente. Lo ideal es que el analista de negocio ayude al cliente a escribir los test
para asegurarse de que las afirmaciones están totalmente libres de ambigüedad.
Los test que pertenecen al Dueño del Producto se llaman test de cliente o de
aceptación. Charlie Poole prefiere llamarles test de cliente, ya que por aceptación se
podría entender que se escriben al final cuando, realmente, no tiene que ser así. De
hecho, en TDD partimos de test de aceptación (ATDD) para conectar requerimientos
con implementación, o sea, que los escribimos, antes que nada. Cuando se escribe el
código que permite ejecutar este test, y se ejecuta positiva mente, se entiende que el
cliente acepta el resultado. Por esto se habla de aceptación. Y también por esto es un
término provocador, al haber clientes que niegan que un test de aceptación positivo
signifique que aceptan esa parte del producto. (Blé Jurado, 2010, https://n9.cl/81eup).
Las pruebas unitarias aíslan una parte del código y comprueban que funciona correctamente. Son
pequeños test que valoran el comportamiento de un objeto. El unit testing suele realizarse durante la
fase de desarrollo de aplicaciones de software o móviles.
Desde el aspecto potestad, es decir, mirando los test según a quién le pertenecen,
distinguimos entre test escritos por desarrolladores y test escritos por el Dueño del
Producto. Recordemos que el Dueño del Producto es el analista de negocio o bien el
propio cliente. Lo ideal es que el analista de negocio ayude al cliente a escribir los test
para asegurarse de que las afirmaciones están totalmente libres de ambigüedad.
Los test que pertenecen al Dueño del Producto se llaman test de cliente o de
aceptación, esto tiene como referencia, ya que por aceptación se podría entender que
se escriben al final cuando, realmente, no tiene que ser así. De hecho, en TDD partimos
del test de aceptación (ATDD) para conectar requerimientos con implementación, o sea,
que los escribimos, antes que nada. Cuando se escribe el código que permite ejecutar
este test, y se ejecuta positivamente, se entiende que el cliente acepta el resultado.
Por esto se habla de aceptación. Y también por esto es un término provocador, al haber
clientes que niegan que un test de aceptación positivo signifique que aceptan esa parte
del producto.
Son los test más importantes para el practicante TDD, los ineludibles. Cada test unitario
o test unidad (unit test en inglés) es un paso que andamos en el camino de la
implementación del software. Todo test unitario debe ser:
Atómico.
Independiente.
Inocuo.
Rápido.
Atómico significa que el test prueba la mínima cantidad de funcionalidad posible. Esto
es, probará un solo comportamiento de un método de una clase. El mismo método
puede presentar distintas respuestas ante distintas entradas o distinto contexto. El test
unitario se ocupará exclusivamente de uno de esos comportamientos, es decir, de un
único camino de ejecución.
A veces, la llamada al método provoca que internamente se invoque a otros métodos;
cuando esto ocurre, decimos que el test tiene menor granularidad, o que es menos fino.
Lo ideal es que los test unitarios ataquen a métodos lo más planos posibles, es decir,
que prueben lo que es indivisible. La razón es que un test atómico evita tener que usar
el depurador para encontrar un defecto en el SUT, puesto que su causa será muy
evidente.
Como veremos en la parte práctica, hay veces que vale la pena ser menos estrictos
con la atomicidad del test, para evitar abusar de los dobles de prueba.
Inocuo significa que no altera el estado del sistema. Al ejecutarlo una vez, produce
exactamente el mismo resultado que al ejecutarlo veinte veces. No altera la base de
datos, ni envía emails ni crea ficheros, ni los borra. Es como si no se hubiera
ejecutado.
Rápido tiene que ser porque ejecutamos un gran número de test en pocos minutos y se
ha demostrado que tener que esperar unos cuantos segundos cada rato, resulta muy
improductivo. Un solo test tendría que ejecutarse en una pequeña fracción de segundo.
La rapidez es tan importante que Kent Beck ha desarrollado recientemente una
herramienta que ejecuta los test desde el IDE Eclipse mientras escribimos código, para
evitar dejar de trabajar en código mientras esperamos por el resultado de la ejecución.
Se llama JUnit Max. Olof Bjarnason ha escrito otra similar y libre para Python.
Para conseguir cumplir estos requisitos, un test unitario aísla la parte del SUT que
necesita ejercitar de tal manera que el resto está inactivo durante la ejecución. Hay
principalmente dos formas de validar el resultado de la ejecución del test: validación del
estado y validación de la interacción, o del comportamiento. En los siguientes capítulos
los veremos en detalle con ejemplos de código.
Los desarrolladores utilizamos los test unitarios para asegurarnos de que el código
funciona como esperamos que funcione, al igual que el cliente usa los test de cliente
para asegurarse que los requisitos de negocio se alcancen como se espera que lo
hagan.
FIRST
Como los acrónimos no dejan de estar de moda, cabe destacar que las características
de los test unitarios también se agrupan bajo las siglas FIRST que vienen de: fast,
independent, repeatable, small y transparent (rápido, independiente, repetible,
pequeño y transparente)
Repetible encaja con inocuo, pequeño caza con atómico y transparente quiere decir que
el test debe comunicar perfectamente la intención del autor. (Blé Jurado, 2010,
https://n9.cl/81eup).
Un framework de pruebas unitarias se define como una herramienta que permite escribir pruebas sobre
un bloque de código. Esta herramienta se ejecuta bajo un entorno de “javascript” sin necesidad de que
interfiera en el IDE ni en la propia aplicación.
Cuando estamos realizando pruebas unitarias sobre nuestro código, muchas veces es
complicado realizar pruebas de métodos que interactúan con componentes de terceros
o que requieren de la existencia de cierta información que no se dispone en la prueba.
Este tipo de problemática, bastante común en el desarrollo de pruebas unitarias, se
resuelve con herramientas que permiten simular una funcionalidad o sobrescribir un
comportamiento existente. Estos objetos simulados (mock) pueden implementarse
utilizando diferentes librerías las cuales cada una de ellas tiene sus ventajas y
desventajas.
Dentro del ámbito de las pruebas unitarias el framework PHPUnit es por lejos el más
utilizado por todos, el cual implementa todas las funcionalidades para desarrollar de
forma eficiente las pruebas requeridas. Este framework incluye los componentes que
permite realizar un mock de clases y métodos, que si bien tiene la mayoría de las
funcionalidades necesarias muchas veces es un poco tedioso escribir las mismas.
PHPUnit
$mock= $this->getMock('Logger');
$mock->expects($this->once())
->method('addInfo')
->with($this->equalTo('bar'))
->will($this->returnValue(true));
Ventajas Desventajas
Mockery
Una librería que se aplica sobre un framework de pruebas unitarias (como PHPUnit) y
que permite extender y simplificar todo lo relacionado con el “mockeo” (perdón RAE) de
objetos y clases. Si bien Mockery tiene una sintaxis muy simple de comprender,
dispone de un arsenal de funcionalidades que lo hacen un aliado poderoso a la hora de
simular objetos. El ejemplo anterior podemos expresarlo usando Mockery de la
siguiente forma:
$mock = Mockery::mock('Logger');
$mock->shouldReceive('addInfo')
->once()
->with('bar')
->andReturn(true);
Como se puede apreciar, la sintaxis para el “mockeo” del método es mucho más
sencilla y fácil de leer. Esto es un ejemplo muy simple, pero a medida que se hace más
complejo lo que se quiere simular (como resultados dinámicos, parámetros dinámicos, o
“mockeos” parciales) se torna mucho más evidente la simplicidad de sintaxis de la cual
dispone. (Citroni, 2016, https://n9.cl/5izuh).
Ventajas Desventajas
+ Sintaxis simple.
Es un framework muy potente que permite realizar ciertas acciones que a los otros
frameworks le cuestan o le son imposibles. Si bien AspectMock no tiene la mayor
legibilidad permite realizar el mockeo de cualquier clase, incluyendo las del propio PHP,
así como también de funciones sueltas. Además, permite mockear clases estáticas, lo
cual puede ser de mucha ayuda en ciertos frameworks (como Laravel). En nuestro
ejemplo anterior, realizar el mockeo del método addInfo de la clase Logger se debería
implementar de la siguiente manera.
$mock = test::double('Logger',
Con una sintaxis muy reducida, que en ciertos casos puede volverse un poco compleja
de leer, AspectMock es el mejor aliado a la hora de mockear clases y métodos, ya que
permite realizar lo mismo que los frameworks anteriores con el agregado de poder
simular clases estáticas, funciones del sistema y la posibilidad de implementar TDD de
una manera muy simple. (Citroni, 2016, https://n9.cl/5izuh).
Ventajas Desventajas
Ventajas Desventajas
Lo bueno de estos frameworks es que no necesitamos casarnos con uno solo de ellos,
sino que, como todos los aspectos de la tecnología, podemos utilizar el que mejor se
ajuste a nuestras necesidades en cada proyecto. (Citroni, 2016, https://n9.cl/5izuh).
Caso 1
La prueba unitaria debe ser capaz de cubrir todas las posibles funcionalidades en un mismo bloque de
código.
Tenemos un módulo que nos exporta el método “getObjectDescription” al que pasándole
como parámetro el “type” nos devuelve un “string”. Ahora bien, identifiquemos los
diferentes casos que se nos pueden dar con dicho módulo:
Estos son, a primera vista, los casos de uso que se pueden presentar en dicho bloque
de código. (Paradigma Digital, 2020, https://cutt.ly/5m0UkVv).
Para los efectos de este ejemplo, utilizaremos JEST que está basado en Jasmine. Esto nos servirá para
demostrar bien el test que estamos planteando.
Es importante aclarar que esta aplicación es para JavaScript, por lo que requiere que el participante
tenga, por lo menos, un conocimiento mínimo de este lenguaje para poder comprender mejor el ejercicio.
Sin embargo, se ha comentado cada sección del código para que se pueda entender la funcionalidad y el
proceso que se busca alcanzar con él.
Una vez que tengamos nuestra estructura de fichero, vamos con los test.
Denominar al método “getObjectDescription” con un parámetro vacío de igual manera que en el test
anterior.
Siguiendo estos pasos, el test debería tener como resultado algo parecido a lo que muestra la siguiente
figura.
Todo ello conlleva unas acciones que, para tener un test correcto, hay que cubrir en la
mayoría de posibilidades o casos que se puedan dar en nuestro código. (Pérez, 2020,
https://n9.cl/jw88r).
Caso 2
Lo primero que vamos a hacer es crear un fichero con el código “javascript”, ya que
este será el código donde realizaremos los test.
Continuamos creando una carpeta en nuestro proyecto llamada test, ya que allí
guardaremos todos nuestros test.
Una vez dentro de la carpeta test, crearemos un fichero y lo llamaremos igual que el
fichero donde está el código “javascript” en el que vamos a realizar el test.
expect(sumar(1,1)).toBe(2);
});
expect(restar(1,1)).toBe(0);
});
expect(multiplicar(1,1)).toBe(1);
});
expect(dividir(1,1)).toBe(1);
});
});
Con nuestro fichero ya creado vamos a ejecutar el test, y para eso crearemos una tarea
en la sección scripts dentro del package.json:
"name": "JEST",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-jest": "^23.6.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"jest": "^23.6.0"
Ahora solo queda ejecutar nuestro test, y para ello usaremos la tarea que habíamos
creado en el package.json usando el siguiente comando: npm run test (test es el
nombre del key asociado al comando que ejecutará) o npm t (forma abreviada).
> jest
PASS test/index.test.js
Operaciones matemáticas
√ Realizamos la resta.
√ Realizamos la multiplicación.
√ Realizamos la división.
Test Suites: 1 passed, 1 total.
Snapshots: 0 total.
Time: 1.465 s.
Jest usa los matchers para probar los diferentes valores que puede tener nuestro
código. (Tecnops.es, 2018, https://n9.cl/xd7rm).
Conclusión
Sin duda, los testeos son muy importantes y nos dan una tranquilidad muy grande a la
hora de poner un sistema en producción. Mientras más temprano obtengamos
resultados, más eficientes seremos en nuestro objetivo de garantizar el rendimiento
(performance) de un sistema.
Para aportar valor en una prueba, se necesita sumar mucha experiencia en pruebas y
tener una vocación muy grande por entender “a bajo nivel” cómo funcionan las cosas.
Esta variedad de skills (habilidades) que se necesitan para este tipo de rol es una de
las cosas que lo hace apasionante. Siempre aparecen tecnologías nuevas, siempre hay
soluciones más complejas, ¡siempre hay un desafío! Nosotros muchas veces decimos
que en este tipo de proyectos jugamos al “Doctor House”, ya que una tarea fundamental
es poder diagnosticar precisamente qué le pasa al sistema y sugerir posibles
soluciones. Y jugando a los médicos, debemos distinguir SÍNTOMAS de CAUSAS.
Nosotros queremos observar los síntomas, y con base en nuestra experiencia ser
capaces de determinar las causas y así poder recetar una solución a nuestro paciente,
a nuestro sistema bajo pruebas. Muchas veces esto se hace preguntando reiteradas
veces: ¿por qué sucede este síntoma? Por ejemplo:
¿Causa o síntoma?
¿Causa o síntoma?
¿Causa o síntoma?
¿Causa o síntoma?
Pasar de una causa a una solución generalmente es fácil, al menos para una persona
con experiencia en esa área. En este caso el experto de base de datos agregaría un
índice adecuado y esto resolvería la causa, que haría que se eviten los síntomas
presentados. De esta forma, con esta prueba, solucionamos el problema que
detectamos. De otro modo, los usuarios hubiesen sufrido esas demoras, y el experto de
base de datos hubiese tenido muchas quejas, y tendría que haber ajustado estos
parámetros en producción con los riesgos e impactos que esto pueda tener. (Toledo,
2014, pp. 169-170).
Preguntas de reflexión
Si tuvieras JEST como herramienta de gestión para automatizar las aplicaciones de un equipo de
desarrollo:
¿Con qué otro tipo de test podrías complementar el testing unitario y por qué?
Si tuvieras que definir en pocas palabras las bondades de los test automatizados: ¿qué dirías?
C O NT I NU A R
Lección 4 de 6
Glosario
Término Descripción
“Conjunto de prácticas
que combina las
operaciones de TI (OPS)
y el desarrollo de
software (DEV). Su
objetivo es acortar el ciclo
DEVOPS
de vida del desarrollo de
sistemas y proporcionar
una entrega continua con
software de alta calidad”.
(LinkFang.org, s. f.,
https://n9.cl/7bgig).
Es el entorno o marco de
Framework
trabajo
Es un Software de control
Git
de versiones.
Un entorno de desarrollo
integrado es una
aplicación que ofrece
IDE
servicios integrales que
simplifican el desarrollo
de software.
“Es un lenguaje de
programación y una
plataforma informática
comercializada por
primera vez en 1995 por
Sun Microsystems. Hay
Java muchas aplicaciones y
sitios web que no
funcionarán a menos que
tenga Java instalado y
cada día se crean más”
(Java, s. f.,
https://n9.cl/pndn).
Sistema de gestión de
bases de datos. En la
MySQL
actualidad, es el más
utilizado en el mundo.
“PostgreSQL es un
sistema de base de datos
relacional de alta
disponibilidad. Es capaz
de funcionar de manera
estable en el servidor y,
PostgreSQL
por lo tanto, resulta
robusto, una de las
principales características
que buscan las empresas”
(Arsys, 2018,
https://n9.cl/ouvvi).
“Conjunto de programas,
instrucciones y reglas
informáticas para ejecutar
Software
ciertas tareas en una
computadora” (RAE,
2020, https://n9.cl/c40v).
TDD “Test-driven
development (TDD) es
una práctica para
desarrollo de software
consistente en la
repetición de un ciclo
breve en el que primero
se codifica un caso para
automatizar la prueba de
la función que se quiere
programar” (Scrum
Manager, 2021,
https://n9.cl/g7krj).
Stack Prueba
Legacy Heredados
Se utiliza para la
Diff
comparación de archivos
Plugin Complemento
Arrange Organiza
Act Actúa
Assert Confirmar
Rápido, independiente,
Fast, independent, repeatable, small y transparent repetible, pequeño y
transparente
AddInfo Agregar información
Logger Registradora
Performance Rendimiento
Skills Habilidades
C O NT I NU A R
Lección 5 de 6
Video de habilidades
Verify to continue
We detected a high number of errors from your
connection. To continue, please confirm that
you’re a human (and not a spambot).
Resolución M3.docx.pdf
663.6 KB
C O NT I NU A R
Lección 6 de 6
Referencias
Arsys (2018). Por qué elegir PostgreSQL y llevarlo a Cloud. Recuperado de:
https://www.arsys.es/blog/soluciones/postgresql-servidores/
Blé Jurado, C. (2010). Diseño ágil con TDD. iExpertos. Recuperado de: https://docplayer.es/28469-
Diseno-agil-con-tdd-carlos-ble-jurado-y-colaboradores-prologo-de-jose-manuel-beas.html
Citroni, A. (26 de febrero de 2016). Frameworks de mock de objetos para pruebas unitarias. Folder It.
Recuperado de: https://folderit.net/es/blog/frameworks-de-mock-de-objetos-para-pruebas-unitarias-es/
Daityari, S. (30 de diciembre de 2020). Las 12 mejores herramientas de revisión de código para
desarrolladores (edición 2021). Kinsta Blog. Recuperado de: https://kinsta.com/es/blog/herramientas-de-
revision-de-codigo/
Java (s. f.). ¿Qué es la tecnología Java y para qué la necesito? Recuperado de:
https://www.java.com/es/download/help/whatis_java.html
Larrosa, D., Delgado Dapena, M. y Fernández Oliva, P. (2018). Diseño y ejecución de pruebas
unitarias en diferentes lenguajes. XVII Convención y Feria Internacional Informática 2018: Universidad
Tecnológica de La Habana. Recuperado de:
https://www.researchgate.net/publication/324017462_DISENO_Y_EJECUCION_DE_PRUEBAS_UNITARI
AS_EN_DIFERENTES_LENGUAJES
Paradigma Digital (5 de noviembre de 2020). ¿Cómo hacer test unitarios en Javascript? Una pequeña
introducción. Paradigma Digital. Recuperado de: https://paradigma-digital.medium.com/cómo-hacer-test-
unitarios-en-javascript-una-pequeña-introducción-e9af3e7a0c50
Pérez, B. (2020). Test unitarios en Javascript: una pequeña introducción. Paradigma Digital. Recuperado
de: https://www.paradigmadigital.com/dev/test-unitarios-javascript-introduccion/
Real Academia Española (2020). Software [Definición]. Diccionario de la lengua española. Recuperado
de: https://dle.rae.es/software
Red Hat (2021). ¿Qué son las API y para qué sirven? Recuperado de:
https://www.redhat.com/es/topics/api/what-are-application-programming-interfaces
Soto Morales, V. M. (20 de mayo de 2021). Conoce qué son las pruebas no funcionales de software.
Academia Pragma. Recuperado de: https://www.pragma.com.co/blog/conoce-que-son-las-pruebas-no-
funcionales-de-software
Tecnops (2018). ¿Por qué hacer testing en Javascript? Tecnops. Recuperado de:
https://tecnops.es/testing-en-javascript-con-jest-parte-1-de-2/
Tester House (26 de marzo de 2019). Pruebas funcionales / No funcionales. ¿Qué son y para qué
sirven? Tester House. Recuperado de: https://testerhouse.com/teoria-testing/pruebas-funcionales/
Toledo, F. (2014). Introducción a las pruebas de sistemas de información. Montevideo: Abstracta.
Recuperado de: https://studylib.es/doc/7273511/introducción-a-las-pruebas-de-sistemas-de-información
Vargas, C. (s. f.). Tipos de pruebas funcionales para el aseguramiento de la calidad. Trycore.
Recuperado de: https://trycore.co/transformacion-digital/tipos-de-pruebas-funcionales/
Visure (s. f.). Microsoft TFS (Azure DevOps). Recuperado de: https://visuresolutions.com/es/microsoft-
tfs-azure/
C O NT I NU A R