Disseny de Proves (TDD)¶
Abans de programar, cal planificar les proves. En aquest document veurem com aplicar el procés TDD complet: des de l'anàlisi de requisits fins a la implementació.
1. Analitzar requisits¶
El primer pas és entendre què ha de fer la funcionalitat. A partir de la descripció, extraiem les regles de negoci.
Exemple: Calculadora
Volem crear una classe Calculadora que faci les quatre operacions bàsiques: suma, resta, multiplicació i divisió.
Regles de negoci:
- La suma de dos nombres retorna el resultat correcte.
- La resta de dos nombres retorna el resultat correcte.
- La multiplicació de dos nombres retorna el resultat correcte.
- La divisió de dos nombres retorna el resultat correcte.
- La divisió per zero ha de llançar una excepció.
- Les operacions han de funcionar amb nombres decimals.
- Les operacions han de funcionar amb nombres negatius.
2. Definir casos de prova¶
Un cop tenim les regles, les convertim en una taula de casos de prova. Per cada cas definim: l'entrada, el resultat esperat i el tipus de test.
| # | Cas de prova | Entrada | Resultat esperat | Tipus |
|---|---|---|---|---|
| 1 | Suma de dos positius | suma(2, 3) |
5.0 |
Unitari |
| 2 | Suma amb zero | suma(5, 0) |
5.0 |
Unitari |
| 3 | Suma de negatius | suma(-2, -3) |
-5.0 |
Unitari |
| 4 | Resta bàsica | resta(10, 3) |
7.0 |
Unitari |
| 5 | Resta amb resultat negatiu | resta(3, 10) |
-7.0 |
Unitari |
| 6 | Multiplicació bàsica | multiplica(4, 3) |
12.0 |
Unitari |
| 7 | Multiplicació per zero | multiplica(5, 0) |
0.0 |
Unitari |
| 8 | Divisió bàsica | divideix(10, 2) |
5.0 |
Unitari |
| 9 | Divisió amb decimals | divideix(7, 2) |
3.5 |
Unitari |
| 10 | Divisió per zero | divideix(5, 0) |
Excepció | Unitari |
Consells per triar casos de prova
- Camí normal: el cas normal, que hauria de funcionar sempre.
- Valors límit: zero, nombres negatius, valors molt grans.
- Casos d'error: entrades invàlides que han de produir errors controlats.
3. Escriure els tests (Red)¶
Ara escrivim els tests abans d'implementar la classe Calculadora. En aquest moment, el codi no compilarà perquè la classe encara no existeix. Això és normal al TDD — és la fase Red.
Creem el fitxer CalculadoraTest.kt a la carpeta app/src/test/java/com/example/app/:
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
class CalculadoraTest {
private lateinit var calc: Calculadora
@Before
fun setUp() {
calc = Calculadora()
}
// --- SUMA ---
@Test
fun suma_deDosPositius_retornaResultatCorrecte() {
val resultat = calc.suma(2.0, 3.0)
assertEquals(5.0, resultat, 0.001)
}
@Test
fun suma_ambZero_retornaElMateixNombre() {
val resultat = calc.suma(5.0, 0.0)
assertEquals(5.0, resultat, 0.001)
}
@Test
fun suma_deDosNegatius_retornaNegatiu() {
val resultat = calc.suma(-2.0, -3.0)
assertEquals(-5.0, resultat, 0.001)
}
// --- RESTA ---
@Test
fun resta_basica_retornaResultatCorrecte() {
val resultat = calc.resta(10.0, 3.0)
assertEquals(7.0, resultat, 0.001)
}
@Test
fun resta_ambResultatNegatiu_retornaNegatiu() {
val resultat = calc.resta(3.0, 10.0)
assertEquals(-7.0, resultat, 0.001)
}
// --- MULTIPLICACIÓ ---
@Test
fun multiplica_basica_retornaResultatCorrecte() {
val resultat = calc.multiplica(4.0, 3.0)
assertEquals(12.0, resultat, 0.001)
}
@Test
fun multiplica_perZero_retornaZero() {
val resultat = calc.multiplica(5.0, 0.0)
assertEquals(0.0, resultat, 0.001)
}
// --- DIVISIÓ ---
@Test
fun divideix_basica_retornaResultatCorrecte() {
val resultat = calc.divideix(10.0, 2.0)
assertEquals(5.0, resultat, 0.001)
}
@Test
fun divideix_ambDecimals_retornaResultatCorrecte() {
val resultat = calc.divideix(7.0, 2.0)
assertEquals(3.5, resultat, 0.001)
}
@Test(expected = IllegalArgumentException::class)
fun divideix_perZero_llancaExcepcio() {
calc.divideix(5.0, 0.0)
}
}
En aquest punt els tests NO compilen
Això és correcte! La classe Calculadora encara no existeix. Si intentem executar els tests, obtindrem errors de compilació. Estem a la fase Red del TDD.
4. Implementar el codi mínim (Green)¶
Ara creem la classe Calculadora amb el codi mínim perquè tots els tests passin. No afegim res que no sigui necessari.
Creem el fitxer Calculadora.kt a la carpeta app/src/main/java/com/example/app/:
class Calculadora {
fun suma(a: Double, b: Double): Double {
return a + b
}
fun resta(a: Double, b: Double): Double {
return a - b
}
fun multiplica(a: Double, b: Double): Double {
return a * b
}
fun divideix(a: Double, b: Double): Double {
if (b == 0.0) {
throw IllegalArgumentException("No es pot dividir per zero")
}
return a / b
}
}
Ara executem els tests i haurien de passar tots (fase Green).
5. Refactoritzar (Refactor)¶
En aquest cas la implementació ja és neta, però en casos més complexos podríem:
- Eliminar codi duplicat.
- Millorar noms de variables o funcions.
- Simplificar lògica complexa.
Regla d'or del Refactor
Després de cada canvi, executa els tests. Si algun test falla, desfés el canvi i torna a intentar-ho. Els tests han de seguir verds.
6. Convencions per nomenar tests¶
Una bona convenció per nomenar els tests és:
nomFuncio_condicio_resultatEsperat
Exemples:
suma_deDosPositius_retornaResultatCorrectedivideix_perZero_llancaExcepciomultiplica_perZero_retornaZero
Això fa que quan un test falla, el nom ja t'explica què s'estava provant i què hauria de passar.
7. Consells per escriure bons casos de prova¶
Valors límit¶
Prova sempre amb valors als extrems del rang esperat:
- Zero
- Nombres negatius
- Cadenes buides
- Llistes buides
- Valors molt grans o molt petits
Casos d'error¶
Comprova que el codi gestiona correctament les situacions d'error:
- Entrades nul·les (
null) - Divisions per zero
- Índexs fora de rang
- Formats incorrectes
Camí normal¶
No oblidis provar el cas normal — el que hauria de funcionar sempre. De vegades ens centrem tant en els casos límit que oblidem provar el cas bàsic.
Un test, una cosa¶
Cada test hauria de comprovar una sola cosa. Si un test falla, has de saber immediatament què ha anat malament. Evita tests que comproven múltiples comportaments alhora.
Resum del procés TDD
- Analitza els requisits i extreu regles de negoci.
- Defineix els casos de prova en una taula.
- Escriu els tests (Red — no compilen).
- Implementa el codi mínim (Green — tots passen).
- Refactoritza mantenint els tests verds (Refactor).
- Repeteix per a la següent funcionalitat.