Desarrollo guiado por pruebas
Es una metodología de desarrollo cuyo objetivo es crear primero las pruebas y luego escribir el software. Sus siglas en Inglés son: Test Driven Development y en español significa: Desarrollo guiado por pruebas.
No es nada nuevo este concepto, incluso muchos de ustedes lectores tendrán menos edad que esta metodología. Fue a finales de los años 80 donde se comenzó a utilizar esta metodología de desarrollo.
Para el uso del TDD se deben combinar 2 metodologías: Test-first development
(escribir las pruebas primero) y Refactoring
(refactorización de código). Para esto, se usa un ciclo de desarrollo que consta de 3 partes principales:
- La prueba debe fallar. (Red: Muchas herramientas muestran los fallos de las pruebas en rojo)
- La prueba debe pasar. (Green: Al igual que lo anterior, las herramientas muestran las pruebas que pasan en verde)
- Se debe mejorar el código. (Refactoring)
Si por alguna razón tu no refactorizas tu código, ya no se cumple con el ciclo del TDD y simplemente sería un Test-first development. Nota personal: En tecnología nos encanta poner nombres diferentes por cualquier cambio
.
Ventajas del TDD
- Puedes mejorar el código de tu aplicación en cualquier momento sin miedo a que dañes algo, ya que las pruebas ya las tienes listas y deberán pasar siempre.
- Los test que realizamos sobre las interfaces de nuestra app no siempre son completos, generalmente es lo que nos acordamos probar.
- Los equipos de testing, development y analyst serán más felices.
- La lectura del código será mucho mejor al tener ejemplos de uso (las pruebas).
Herramientas
Dependiendo del lenguaje de programación, puedes escoger entre decenas de frameworks que te permitirán hacer pruebas, algunos conocidos son:
- Java - JUnit, REST assured, Selenium, Mockito, Spock, etc.
- JavaScript - Jasmine, AVA, Tape, Mocha, Jest, etc.
- PHP - PHPUnit, Codeception, Behat, PHPSpec, SimpleTest, Storyplayer, etc.
- Python - $&https://wiki.python.org/moin/PythonTestingToolsTaxonomy\$&(clic para ver algunas herramientas)
- Go - El paquete testing nativo de Go.
No pregunten cual framework es el mejor para tu lenguaje de programación, prueben con varios y escojan con el que mejor se sientan.
Manos a la obra
Hagamos un TDD para el factorial de un número:
- Creamos la prueba en el archivo
factorial\_test.go
:
1package factorial 2 3import "testing" 4 5func TestFactorial(t *testing.T) { 6 result := Factorial(5) 7 want := 120 8 if result != want { 9 t.Errorf("Se esperaba %d, se obtuvo: %d", want, result) 10 } 11} 12
Si ejecutamos la prueba fallará la primera vez ya que no existe la función Factorial(n int)
, pero esa no es la falla que queremos, las fallas de compilación no cuentan, así que debemos crear un código que cumpla con el resultado esperado.
- Creamos el código que cumpla la prueba en el archivo
factorial.go
:
1package factorial 2 3func Factorial(n int) int { 4 return 120 5} 6
Ahora tenemos una función que cumple con lo solicitado. Obviamente no estamos calculando un factorial de manera correcta, pero aún no lo sabemos, ya que si ejecutamos la prueba, esta pasará sin problemas. Así que vamos a agregar más pruebas para comprobar que el código funciona:
- Agregamos más pruebas a nuestro archivo
factorial\_test.go
:
1package factorial 2 3import "testing" 4 5func TestFactorial(t *testing.T) { 6 table := []struct{ 7 Fact int 8 Want int 9 }{ 10 {1, 1}, 11 {2, 2}, 12 {3, 6}, 13 {4, 24}, 14 {5, 120}, 15 } 16 17 for _, v := range table { 18 result := Factorial(v.Fact) 19 if result != v.Want { 20 t.Errorf("Se esperaba %d, se obtuvo: %d", v.Want, result) 21 } 22 } 23} 24
- Ahora escribiremos el código para que realmente funcione el factorial. Archivo
factorial.go
:
1package factorial 2 3func Factorial(n int) int { 4 r := 1 5 for i := n; i > 1; i-- { 6 r *= i 7 } 8 9 return r 10} 11
Perfecto, ahora nuestras pruebas pasan totalmente. Pero, aún nos falta algo... la refactorización del código. Pues ahora necesitamos utilizar recursividad para resolver el problema ya que con ciclos nuestro proceso se convierte en un infierno (es totalmente hipotético, utilizo el ejemplo a manera de metáfora). Entonces manos a la obra, cambiaremos nuestro código sin temor a dañar algo ya que nuestras pruebas revisarán que nuestro código siga haciendo lo que necesitamos que haga:
- Refactorización del archivo
factorial.go
:
1package factorial 2 3func Factorial(n int) int { 4 if n == 0 || n == 1 { 5 return 1 6 } 7 8 return Factorial(n-1) * n 9} 10
Voila! las pruebas pasan sin preocupaciones y pudimos refactorizar nuestro código.
No esperes más, comienza ya mismo a hacer tus Test-first development
y luego refactoriza tu código para terminar realizando un buen TDD
.
Nos vemos en el EDcamp Lima 2018, no olvides comprar tus entradas en: https://ed.team/edcamp