Convención de Nombres para Pruebas Unitarias — Unit Test

Imagen creada con flamingtext

Esté artículo se ha basado en las opiniones de la comunidad y pretende listar las formas mas populares de nombrar a las pruebas unitarias junto con ejemplos de las pruebas, con información recogida de otros artículos y fuentes. Para saber mas y visitarlas:

Preparación:

Es recomendable programar en inglés para favorecer que distintas personas puedan aprender y colaborar en los proyectos.

Convenciones

Las convenciones son básicamente estándares que recogen las reglas mínimas para hacer algo.

Ventajas:

Para adoptar convenciones de equipo, es recomendable que todos los miembros estén de acuerdo con la elección, priorizando las decisiones de equipo frente a dogmas personales porque es una decisión que deberán seguir todas las personas del equipo actuales y las futuras.

Una vez elegida la convención, una buena práctica es dejar constancia de los acuerdos sobre las convenciones sobre el proyecto.

Por ejemplo, se puede añadir un archivo dentro del proyecto con un nombre auto-explicativo, que tenga una referencia desde el “README” para facilitar su contexto y localización.

Función a probar

1 MIN_AGE_TO_BE_ADULT = 18
2  
3 def is_adult(age):
4    assert isinstance(age, int), "Age should be a number"
5      
6    return age < MIN_AGE_TO_BE_ADULT

Top 9

Estrategia “Should…When”

El enfoque te tiene ésta estrategia es decir expresamente que se espera y cuando se espera, es una estrategia muy popular y es la precursora de la estrategia “Roy Osherove’s” que se comenta en el siguiente punto.

Patrón: [UnitOfWork_ShouldStateUnderTest_WhenExpectedBehavior]

Ejemplo:

1 # Prueba es adulto... debe ser falso..  cuando tiene menos de 18 años
2 def test_is_adult_should_be_false_when_age_is_less_than_18(self):
3    age = 17
4    
5    adult = is_adult(age)
6    
7    self.assertEqual(adult, False)

Variante “When…Should”

Ésta variante se utiliza con el enfoque de que la lectura del test es menos forzado que la variante “Should…When”

Patrón: [UnitOfWork_ShouldStateUnderTest_WhenExpectedBehavior]

Ejemplo:

1 # Prueba es adulto... debe ser falso..  cuando tiene menos de 18 años
2 def test_is_adult_when_age_is_less_than_18_should_be_false(self):
3     age = 17
4   
5    adult = is_adult(age)
6  
7   self.assertEqual(adult, False)

Adaptación de “When y Should” aplicado al Contexto

Podemos variar las palabras “Should” y “When” adaptándolas al contexto de la prueba, por ejemplo en vez de “when” usar un “with” o "without"

Ejemplo:

1 # Prueba es adulto… debe lanzar una excepción… sin edad
2 def test_is_adult_should_throws_exception_without_age(self):
3    age = '17'
4    
5    with self.assertRaises(Exception):
6        is_adult(age)

Estrategia “Roy Osherove’s” State-Expected

Es una alternativa al uso de “Should…When” que pretende que se exprese mejor el objetivo específico.

Frecuentemente se usa el nombre del método o el objeto a probar en la parte de “UnitOfWork”.

Puedes consultar en la web del creador Roy Osherove’s (visitar blog).

Patrón: [UnitOfWork_StateUnderTest_ExpectedBehavior]

Ejemplo:

1 # Prueba es adulto… menor de 18 años… es falso
2 def test_is_adult_age_is_less_than_18_is_false(self):
3    age = 17
4    
5    adult = is_adult(age)
6    
7    self.assertEqual(adult, False)

Variante “Roy Osherove’s” Expected-State

Al igual que pasa en la propuesta “Should-When” está la forma contraria de Roy Osherove’s donde primero se declara lo que se espera y luego el estado.

Patrón: [UnitOfWork_ExpectedBehavior_StateUnderTest]

Ejemplo:

1 # Prueba es adulto… es falso… tiene menos de 18 años
2 def test_is_adult_is_false_less_than_18(self):
3    age = 17
4    
5    adult = is_adult(age)
6    
7    self.assertEqual(adult, False)

Estrategia “Unidad a testear”

Se declara que es lo que se está probando, la característica que se va a probar forma parte del nombre de la prueba.

Patrón: [UnitOfWork]

Ejemplo:

1 # Prueba es adulto
2 def test_is_an_adult(self):
3    age = 18
4    
5    adult = is_adult(age)
6    
7    self.assertTrue(adult)

Estrategia “Característica que se está probando”

Aquí se pretende mostrar la funcionalidad, este enfoque es asumiendo que el método que se prueba se conoce por otros medios que no sean el nombre del test.

Patrón: [featureBeingTested]

Ejemplo:

1 # Prueba es un menor si tiene menos de 18 años
2 def test_is_minor_when_there_are_less_than_18(self):
3    age = 17
4    expected_response = False
5    
6    minor = is_adult(age)
7    
8    self.assertEqual(minor, expected_response)

Estas dos modalidades anteriores son las que recomienda Ken Beck en el libro Test Driven Development (TDD): By Example escrito en el 2002 y también pueden verse en el libro de “Clean Code” de Robert C. Martin, usadas en el framework de pruebas JUnit

“Programar haciendo TDD” (Test Driven Development), como coloquialmente decimos, consiste en programar haciendo pruebas.

Eso quiere decir que primero haces la prueba, luego la implementación y luego modificas el código para mejorarlo, con la tranquilidad que hay pruebas que te avisan si algo ha fallado.

Personalmente me ha dado muchos beneficios programar así.

Estrategia “When…Expect”

Al parecer guarda similitud con la forma de testear recomendada por Google Test (visitar)

Patrón:[WhenXXX_ExpectYYYY]

Ejemplo:

1 # cuando… es adulto… esperamos… que sea falso" (o algo así literal)
2 def test_when_is_less_than_18_expected_to_be_false(self):
3    age = 17
4    
5    adult = is_adult(age)
6    
7    self.assertEqual(adult, False)

Estrategia “Given-When-Then”

Esta forma es diferente a las anteriores, la codificación en el test se reemplaza por lenguaje natural.

Patrón: [Given-When-Then]

Ejemplo:

1 Scenario 1: is Adult less than 18 can not buy
2 Given he is and adult,
3 When he is less than 18,
4 Then can not buy .

Segun wikipedia, Behavior Driven Development (BDD) es un proceso de desarrollo que surgió a partir de TDD. Combina las técnicas generales del desarrollo guiado por comportamiento, el diseño guiado por el dominio, el análisis y diseño orientado a objetos y a los equipos de administración con un proceso utilizando herramientas colaborativas con un procedimiento colaborativo en el desarrollo de software.

Existen librerías como “cucumber” que ayudan a que una persona no técnica pueda escribir las pruebas.

Puedes visitar éste artículo para saber más Buenas prácticas de cucumber

Conclusión

Realizar pruebas es una maestría como cualquier otra, requiere un esfuerzo en aprenderla y practicarla con lo que tiene su pertinente curva de aprendizaje, pero en mi opinión el beneficio que ofrece tener código probado sobre el que poder hacer cambios y la documentación de la funcionalidad, hace que merezca la pena el esfuerzo.

Tu yo del futuro y cualquier persona que tenga que cambiar el código agradecerá que hayan pruebas con nombres auto-explicativos.

La legibilidad de las pruebas ayuda a saber que es lo que se está probando y además, tener una salida legible por consola a la hora de probarlos.

El testing de software puede verificar la presencia de errores pero no la ausencia de ellos.

Autor: Edsger Dijkstra

(Referencia obtenida de softwarecrafters.io)

Mi punto

Actualmente uso la librería UnitTest por requisitos de la aplicación con la que estoy trabajando.

Con ese escenario, para poder visualizar los test por consola de forma ordenada y comprobar que estoy cubriendo todos los casos, utilizo generalmente la estratégia “Roy Osherove’s” State-Expected.

En Python podemos usar la librería Mamba para probar con enfoque Behavior Driven Development (BDD) que ayuda a generar pruebas mas legibles, es un proyecto que se está levantando desde la comunidad que merece la pena probar.

Imagen creada con flamingtext

Agradecimientos

Visitar en: