TDD Sencillo
Tags: testing, javascript, refactoring
Published: 2023-07-17 11:00:58

- [Introducción](#introducción)
- [Qué es el TDD](#qué-es-el-tdd)
- [Qué nos ofrece](#qué-nos-ofrece)
- [Para qué utilizarlo](#para-qué-utilizarlo)
- [Cómo se pone en marcha](#cómo-se-pone-en-marcha)
    - [Las Tres Leyes](#las-tres-leyes)
        - [Primera ley](#primera-ley)
        - [Segunda ley](#segunda-ley)
        - [Tercera ley](#tercera-ley)
- [Cómo funciona en la práctica](#cómo-funciona-en-la-práctica)
    - [Ciclo uno](#ciclo-uno)
    - [Ciclo dos](#ciclo-dos)
    - [Ciclo tres](#ciclo-tres)
    - [Ciclo cuatro](#ciclo-cuatro)
- [Referencias](#referencias)

----


# Introducción 
Este post lo he basado en el libro del Tio Bob *(Robert C. Martin)*, **La artesanía del código limpio**. Es una lectura muy recomendable ya que amplía muchos conceptos y se desarrollan de forma más extensa de lo que yo pretendo con este post.

> Si te apasiona tanto como a mi el desarrollo de software, te darás cuenta que siempre vas a querer ser mejor desarrollador/a, por lo tanto llegarás a la conclusión de que el TDD aumentará tu habilidad en este sentido y vas a querer ponerlo en práctica. 

# Qué Es El TDD

Es una forma más de escribir código, podemos decir que es una metodología a la hora de programar. El enfoque principal de este proceso son los *(temidos)* tests, pero no es para tanto, además, nos ofrece muchas ventajas. 



# Qué Nos Ofrece

Las ventajas que nos ofrece esta metodología de programar las podemos ver en la siguiente lista:

- Tener un código **fácil** de **leer** y **entender**.
- Tener un código **poco interconectado** entre sí.
- Tener un código **corto** y muy **segmentado**.
- Tener un código **fácil** de **testear**.
- Asegurarnos que nuestro código **funciona bien**.
- Tener un código **escalable**.
- En ocasiones se llega al desarrollo de algoritmos complejos que sin realizar TDD es difícil llegar a la misma solución.

# Para Qué Utilizarlo 
Los programadores lo utilizamos para  asegurar que nuestro trabajo está bien hecho y no falla.

En el peor de los casos se utiliza para evitar muertes *(como bien ha ocurrido en el pasado por fallos de software, Boeing, Tesla...)*

# Cómo Se Pone En Marcha

## Las Tres Leyes
Para entender y aplicar el TDD se describe mediante 3 leyes o principios básicos que siempre debemos seguir para llevarlo a la práctica.

*En mi caso lo entendí al leer dichas leyes y ver ejemplos.*

### Primera Ley
**No escribir nunca un código de producción hasta haber escrito una prueba que falle debido a la falta de dicho código.**

Vamos a testear la clase persona por ejemplo, pero en nuestro desarrollo de momento no existe dicha clase, lo que haremos será escribir un test que instancie un objeto de la clase persona.

### Segunda Ley
**Escribir de un test lo mínimo posible para conseguir que falle o que no compile o ejecute. Resolver el fallo escribiendo código de producción.**

En el ejemplo, escribimos una línea de código y el test fallará (no existe la clase persona). A continuación, como hemos escrito lo mínimo posible en el test, ahora escribimos código de producción para que pase la prueba, por lo tanto creamos una clase persona.

### Tercera Ley
**No escribir más código de producción que el que sea suficiente para pasar la prueba que falla en ese momento. Una vez ha pasado la prueba, escribimos más código de prueba *(volver a la primera ley)***

Para pasar la prueba solo se crea la clase persona y se ejecuta el test, debería de funcionar, entonces ahora hay que escribir otra prueba. Por ejemplo utilizar un método de la clase persona, `setName` por ejemplo. Esta nueva prueba fallará, esto es bueno y es lo que esperamos que ocurra. Ahora volvemos a la primera ley.

### Tercera Ley*
Después de poner en práctica las tres leyes cumplimos el ciclo del TDD, pero antes de empezar un nuevo ciclo lo que debemos hacer si corresponde es refactorizar el código, hacerlo más corto, más sencillo o lo que corresponda en cada caso. 

**La refactorización del anterior código no debe modificar el comportamiento del código**, solo debe modificar el código en sí, y debería de pasar todas las anteriores pruebas.

En este breve ejemplo podemos observar dos cosas:
- Hemos testeado que nuestro código falla.
- Hemos testeado que nuestro código funciona.

Estos dos conceptos son importantes porque por lo general, nosotros, los programadores, casi siempre testeamos código para que funcione, en este caso obligamos a que falle para después arreglar el fallo y así asegurarnos que no falla.

![ciclo tdd](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/77m2jp9vgfpxi2wsccpb.png)


# Cómo Funciona En La Práctica
Vamos a ver el ejemplo anterior de manera práctica y en varios ciclos.

## Ciclo Uno

### 1. Creamos el test que falla
**Test clase persona**
*En este caso uso Javascript y hay que tener en cuenta que si importas un modulo que no se exporte, el test no falla, por lo tanto vamos a escribir un poco mas de código de test para que falle.*

`person.test.js`
```javascript
import { Person } from "./person.js"

describe('Person Suite', () => {
	test('Create Person', () => {
		const p1 = new Person()
	})
})
```

Si ejecutamos el test mediante `jest` veremos que falla, estamos importando un módulo que no existe *(esto no falla)* y estamos intentando instanciar una clase que no existe, aquí es donde falla.

### 2. Añadimos código mínimo de producción para arreglar el fallo

**Creamos clase persona**
`person.js`
```javascript
class Person {
}

export { Person }
```

Con este cambio, el test ya pasa y sabemos que nuestra última versión de código funciona.


### 3. Fin del ciclo *(refactorizar código)*
De momento no hay nada que refactorizar, así que volvemos a empezar el ciclo.

## Ciclo Dos 

### 1. Creamos el test que falla
Ahora quiero añadir un nombre al objeto persona, así que voy a escribir un test que me permita añadir el nombre utilizando un método de la clase *(que aún no existe)*

`person.test.js`
```javascript
...

	test('Should set person name', () => {
		const p1 = new Person()
		p1.setName('Alice')
})
```

Al ejecutar la suite de tests, el primer test sigue pasando, pero el nuevo no pasa, no existe el método `setName`. Por lo tanto vamos a arreglar el código de producción para que pase este test.

### 2. Añadimos código de producción para arreglar el fallo
`person.js`
```javascript
class Person {
	setName(name) {}
}
...
```

Con este sencillo cambio todos nuestros tests pasan y estamos seguros que nuestra última versión de código funciona correctamente.

### 3. Fin del ciclo *(refactorizar código)*
En este paso podríamos refactorizar guardando el nombre en un atributo de la clase por ejemplo, pero vamos a evitar saltar pasos y vamos a otro ciclo.

## Ciclo Tres

### 1. Test qué falla
*Obtener el nombre de la persona*
`person.test.js`
```javascript
...
	test('Should get the name of person', () => {
		const p1 = new Person()
		p1.setName('Alice')

		const name = p1.getName()
		expect(name).toEqual('Alice')
	})
```
### 2. Arreglar fallo
`person.js`
```javascript

class Person {
    setName(name) {
    }

	getName() {
		return 'Alice'	
	}
}
```

Ahora el test pasa y sabemos que la última versión de nuestro código funciona correctamente.

## Ciclo Cuatro 

### 1. Test qué falla
`person.test.js`
```javascript
...
	test('Should get the assigned name of person', () => {
		const name = 'Bob'
		const p1 = new Person()
		p1.setName(name)

                // Parte en la que falla
		const pName = p1.getName()
		expect(pName).toEqual(name)
	})
```
### 2. Arreglar el fallo
`person.js`
```javascript
class Person {
	name = ''
    setName(name) {
		this.name = name
    }

	getName() {
		return this.name
	}
}
```

Y de esta manera podemos ir progresando en el desarrollo de la clase persona hasta complicarla lo máximo posible y sabiendo siempre que la última versión de nuestro código funciona.

También estaremos obligados de manera implícita a escribir código correcto, el tdd nos obliga a ello.

# Referencias


{% embed https://anayamultimedia.es/libro/titulos-especiales/la-artesania-del-codigo-limpio-robert-c-martin-9788441544994/ %}