ACCESO CAMPUS VIRTUAL
¡Llámanos al 919059306!
¡Pide información!

Enter your keyword

Juegos y Desafíos de Código: Practica BDD y TDD de Forma Divertida

Juegos y Desafíos de Código: Practica BDD y TDD de Forma Divertida

Juegos y Desafíos de Código: Practica BDD y TDD de Forma Divertida

Contenidos de la entrada

17 min
5 1 voto
Puntúa la entrada

Si alguna vez has escuchado las siglas BDD (Behavior-Driven Development) o TDD (Test-Driven Development) y te has preguntado: “¿qué es todo esto y por qué debería importarme?”, ¡estás en el lugar correcto! Vamos a desmitificar estos conceptos de manera sencilla, amena y, sobre todo, práctica.

Imagínate que estás construyendo una casa. Antes de empezar a colocar ladrillos, necesitas un plano que te diga cómo debería verse el resultado final. Pues bien, BDD es como ese plano: describe qué debería hacer tu código desde el punto de vista de comportamiento. Por otro lado, TDD es como una revisión constante de la construcción: con cada pequeño avance, compruebas que todo está en orden y que no se ha torcido ni un ladrillo.

Si te ha parecido útil esta analogía y quieres profundizar más en el análisis de código BDD y TDD, te invito a explorar nuestro curso gratuito en Análisis en Código BDD y TDD. En este curso, encontrarás una guía detallada y práctica que te ayudará a entender cómo aplicar estas metodologías de manera efectiva en tus proyectos, asegurando que cada «ladrillo» de tu código esté en su lugar. ¡No te lo pierdas!

¿Por qué BDD y TDD son importantes?

Cuando programamos, muchas veces nos lanzamos a escribir código como si estuviéramos en una carrera de coches. Aceleras, lanzas líneas de código aquí y allá, y de repente… ¡bam! Algo no funciona y no sabes por qué. Es frustrante, ¿verdad? Aquí es donde entran BDD y TDD. Son como tus copilotos en esa carrera, que te guían para que no te salgas de la pista y llegues a la meta sin chocar.

BDD se enfoca en cómo se debería comportar tu software, escrito en un lenguaje que todos puedan entender, ya seas programador o parte del equipo de negocio. Mientras tanto, TDD se centra en escribir pequeñas pruebas antes de escribir el código. Así, te aseguras de que cada línea de código que escribas funcione correctamente.

Un ejemplo para entender mejor

Vamos a hacerlo más claro con un ejemplo sencillo. Imagínate que tienes que programar una calculadora que sume dos números.

  • Con BDD, primero escribirías algo así como: “La calculadora debe sumar correctamente dos números”. Fácil, ¿no? Estás describiendo el comportamiento esperado.
  • Con TDD, escribirías primero una prueba muy sencilla que diga: “Cuando sumo 2 + 3, el resultado debe ser 5”. Y sólo después escribirías el código para hacer que la calculadora realice esa suma.

La clave aquí es que no te lanzas a escribir código sin tener claro lo que esperas que haga. Primero defines qué esperas que pase (BDD), luego aseguras que cada pequeña parte funcione correctamente desde el principio (TDD).

¡Hacer que aprender sea divertido!

¿Y si te digo que puedes aprender estas técnicas mientras juegas? En este artículo, vamos a proponerte juegos y desafíos que te ayudarán a practicar BDD y TDD de una forma entretenida. No necesitas ser un experto para empezar, solo ganas de aprender y divertirte. ¡Así que prepárate, que lo vas a pasar bien mientras aprendes a desarrollar software de una manera mucho más ordenada y eficiente!

Preparativos para el Juego

Antes de que empieces a jugar con el código y a descubrir lo divertido que puede ser practicar BDD y TDD, necesitamos asegurarnos de que tienes todo lo necesario. Piensa en esto como preparar el campo de juego antes de empezar un partido de fútbol: sin una pelota y las reglas claras, el juego no tiene mucha gracia. ¡Vamos allá!

Herramientas Necesarias

Para empezar con BDD y TDD, necesitamos algunas herramientas que te ayuden a poner en práctica estas metodologías. Aquí te dejo las que considero más sencillas y útiles para empezar:

  • Framework de BDD: Cucumber: Cucumber es uno de los frameworks más populares para practicar BDD. Te permite escribir pruebas en un lenguaje casi humano, que todo el equipo (incluso los no programadores) puede entender. Usaremos Cucumber para definir cómo debería comportarse nuestro código.
  • Framework de TDD: JUnit Si estás programando en Java, JUnit es perfecto para TDD. Este framework te permite escribir pruebas antes de ponerte a picar código. Así te aseguras de que tu código hace exactamente lo que debería hacer, ¡sin sorpresas desagradables!
  • Un IDE: Necesitas un buen entorno de desarrollo para escribir código de manera cómoda. Te recomiendo usar IntelliJ IDEA o Visual Studio Code, ambos son bastante amigables para empezar y funcionan de maravilla con Cucumber y JUnit.
  • Java Development Kit (JDK)Como muchos ejemplos de BDD y TDD están en Java, necesitarás tener instalado el JDK en tu ordenador. La versión 11 está bien para nuestros propósitos.

Con estas herramientas, tendrás todo lo necesario para empezar a practicar BDD y TDD. Lo mejor de todo es que la mayoría son gratuitas o tienen versiones gratuitas, así que no necesitas gastar un céntimo.

Configuración Inicial

Ahora que ya tienes tus herramientas listas, vamos a poner todo en marcha. ¡Es como montar una tienda de campaña antes de una excursión! A continuación, te explico los pasos para configurar tu entorno de desarrollo:

  1. Instala JDK: Descarga e instala el JDK desde el sitio oficial de Oracle. Sigue las instrucciones de instalación y asegúrate de que está correctamente configurado en tu sistema. Para comprobar que todo está bien, abre una terminal o consola y escribe:
    java -version

    Deberías ver algo como «java version 11». Si es así, ¡todo va bien!

  2. Configura tu IDE: Abre IntelliJ IDEA o Visual Studio Code. Si estás usando IntelliJ, simplemente crea un nuevo proyecto de tipo «Java» y selecciona la versión de JDK que acabas de instalar.Si prefieres Visual Studio Code, asegúrate de instalar las extensiones para Java y las que correspondan a Cucumber o JUnit.
  3. Instala Cucumber: Para usar Cucumber en tu proyecto de Java, necesitas añadir la dependencia de Cucumber en tu archivo pom.xml si estás usando Maven o en build.gradle si usas Gradle. Aquí tienes un ejemplo para Maven:
    
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>7.0.0</version>
    </dependency>
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit</artifactId>
      <version>7.0.0</version>
    </dependency>
        

    Esto le dirá a Maven que descargue Cucumber para que puedas empezar a usarlo en tu proyecto.

  4. Instala JUnit: Si vas a usar TDD, necesitarás JUnit. Añádelo de la misma manera en tu archivo de dependencias:
    
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
        

    Con esto, ya tendrás JUnit disponible para tus pruebas.

  5. Verifica la Configuración: Ahora que todo está instalado, asegúrate de que tu entorno está listo. Puedes crear una prueba sencilla con JUnit para ver si todo funciona:
    
    import org.junit.Test;
    import static org.junit.Assert.assertEquals;
    
    public class CalculadoraTest {
    
        @Test
        public void sumaDosNumeros() {
            int resultado = 2 + 3;
            assertEquals(5, resultado);
        }
    }
        

    Ejecuta este test y, si todo va bien, verás que la prueba se pasa con éxito. ¡Ya estás listo para empezar con los desafíos!

Con estos preparativos, ya tienes tu «caja de herramientas» lista. En los siguientes desafíos, verás cómo aplicamos tanto BDD como TDD para desarrollar funcionalidades de manera divertida y efectiva. ¡Que empiece el juego!

Desafío 1: La Calculadora Mágica

¡Bienvenido al primer desafío! Vamos a construir una calculadora que realice operaciones básicas como suma, resta, multiplicación y división. Este será nuestro primer paso en el mundo de BDD y TDD, y lo haremos de manera práctica y divertida. Prepárate para escribir pruebas antes de escribir el código, y verás cómo tu calculadora se convierte en una auténtica «calculadora mágica».

Descripción del Desafío

El objetivo de este desafío es desarrollar una calculadora capaz de realizar las siguientes operaciones:

  • Suma
  • Resta
  • Multiplicación
  • División

Lo interesante aquí es que vamos a definir primero el comportamiento que queremos para la calculadora utilizando BDD (Behavior-Driven Development). Es decir, antes de escribir una sola línea de código, describiremos cómo esperamos que funcione nuestra calculadora. Luego, usaremos TDD (Test-Driven Development) para implementar el código necesario asegurándonos de que pase todas las pruebas.

Reglas del Juego

Como en todo buen juego, necesitamos establecer algunas reglas para asegurarnos de que la calculadora funcione como debe:

  1. La calculadora debe poder realizar las operaciones básicas: suma, resta, multiplicación y división.
  2. No se permite la división entre 0 (¡esto provocaría el caos en las matemáticas!).
  3. Las pruebas deben estar escritas antes de implementar el código de las funciones de la calculadora (¡TDD en acción!).
  4. Utiliza BDD para definir claramente el comportamiento esperado en un lenguaje que cualquiera pueda entender, incluso si no sabe programar.

Criterio de éxito: El desafío se completa con éxito cuando todas las operaciones se pueden realizar correctamente y las pruebas unitarias para cada una de ellas pasan sin errores.

Solución y Código de Ejemplo

Paso 1: Definir el Comportamiento con BDD

Primero vamos a definir cómo debería comportarse nuestra calculadora utilizando Cucumber. En BDD, describimos los escenarios de uso de la calculadora en un lenguaje sencillo y comprensible. Aquí usamos el formato Gherkin para escribir las características y comportamientos.


Feature: Operaciones de la Calculadora
  Como usuario quiero realizar operaciones básicas con una calculadora.

  Scenario: Sumar dos números
    Given que tengo una calculadora
    When sumo 2 y 3
    Then el resultado debería ser 5

  Scenario: Restar dos números
    Given que tengo una calculadora
    When resto 5 y 2
    Then el resultado debería ser 3

  Scenario: Multiplicar dos números
    Given que tengo una calculadora
    When multiplico 4 por 5
    Then el resultado debería ser 20

  Scenario: Dividir dos números
    Given que tengo una calculadora
    When divido 10 entre 2
    Then el resultado debería ser 5

  Scenario: Dividir por cero
    Given que tengo una calculadora
    When divido 5 entre 0
    Then debería mostrar un error de "División por cero"

Aquí hemos definido cinco escenarios simples para las operaciones de nuestra calculadora. Observa que el lenguaje es sencillo, de manera que cualquiera puede entender lo que se espera que haga la calculadora.

Paso 2: Escribir Pruebas con TDD

Ahora que tenemos definidos los comportamientos esperados, es hora de pasar a la implementación de pruebas con JUnit. Vamos a escribir las pruebas para cada operación antes de escribir el código de la calculadora.


import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

public class CalculadoraTest {

    @Test
    public void sumaDosNumeros() {
        Calculadora calculadora = new Calculadora();
        assertEquals(5, calculadora.sumar(2, 3));
    }

    @Test
    public void restaDosNumeros() {
        Calculadora calculadora = new Calculadora();
        assertEquals(3, calculadora.restar(5, 2));
    }

    @Test
    public void multiplicaDosNumeros() {
        Calculadora calculadora = new Calculadora();
        assertEquals(20, calculadora.multiplicar(4, 5));
    }

    @Test
    public void divideDosNumeros() {
        Calculadora calculadora = new Calculadora();
        assertEquals(5, calculadora.dividir(10, 2));
    }

    @Test
    public void lanzaExcepcionAlDividirPorCero() {
        Calculadora calculadora = new Calculadora();
        assertThrows(ArithmeticException.class, () -> calculadora.dividir(5, 0));
    }
}

Estas pruebas cubren los comportamientos que definimos anteriormente con BDD. Cada operación tiene una prueba que valida que nuestra calculadora funciona correctamente.

Paso 3: Implementar la Calculadora

Finalmente, después de tener nuestras pruebas escritas, ¡es hora de implementar el código que haga que estas pruebas pasen!


public class Calculadora {

    public int sumar(int a, int b) {
        return a + b;
    }

    public int restar(int a, int b) {
        return a - b;
    }

    public int multiplicar(int a, int b) {
        return a * b;
    }

    public int dividir(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("División por cero no permitida");
        }
        return a / b;
    }
}

Con este código, implementamos las funciones básicas de la calculadora. Ahora, cuando ejecutes tus pruebas, deberían pasar sin problemas si todo está bien.

Paso 4: Comprobar el Resultado

Ejecuta todas las pruebas que escribimos con JUnit. Si todas se ejecutan con éxito, ¡felicidades! Has completado el desafío y creado tu propia calculadora mágica que cumple con las expectativas definidas usando BDD y las valida con TDD.

¡Ahora estás listo para pasar al siguiente desafío!

Desafío 2: La Tienda de Mascotas Virtual

¡Bienvenido al segundo desafío! Esta vez, vamos a crear un sistema para gestionar una tienda de mascotas. Aplicaremos BDD para definir los requisitos de la tienda y TDD para asegurarnos de que todo el código funciona correctamente. Con este desafío, aprenderás a manejar un sistema más complejo, interactuando con inventarios y pedidos, todo mientras garantizamos que el código es robusto y cumple con los requisitos.

Descripción del Desafío

En este desafío, vamos a desarrollar un sistema que permita gestionar las operaciones básicas de una tienda de mascotas virtual. Aquí están las funcionalidades que vamos a implementar:

  • Registrar nuevas mascotas en la tienda (nombre, tipo de animal, precio).
  • Mostrar el inventario de mascotas disponibles.
  • Realizar compras de mascotas (se reducirá el inventario de esa mascota).
  • Mostrar un recibo tras la compra de una mascota.

Para abordar este desafío, comenzaremos escribiendo los requisitos de comportamiento utilizando BDD. A continuación, usaremos TDD para escribir pruebas antes de implementar las funcionalidades. Así nos aseguramos de que el código cumple con los requisitos desde el principio.

Reglas del Juego

Como en el desafío anterior, estableceremos algunas reglas para que el juego tenga sentido y puedas asegurarte de que todo funciona correctamente:

  1. La tienda debe poder añadir mascotas al inventario con nombre, tipo y precio.
  2. Debe ser posible visualizar el inventario de mascotas disponibles.
  3. Cuando se compra una mascota, se debe reducir el número disponible en el inventario.
  4. Si se compra una mascota que ya no está en inventario, debe mostrarse un mensaje de error.
  5. Después de cada compra, se debe generar un recibo con el nombre de la mascota y el precio pagado.

Criterio de éxito: Completarás el desafío con éxito cuando todas las funcionalidades estén implementadas y pasen las pruebas de TDD, garantizando que la tienda de mascotas funciona correctamente bajo los requisitos definidos.

Solución y Código de Ejemplo

Paso 1: Definir el Comportamiento con BDD

Primero, definimos los escenarios del comportamiento esperado de nuestra tienda de mascotas utilizando Cucumber. Aquí describimos los requisitos clave en un formato simple que cualquiera pueda entender:


Feature: Gestión de la tienda de mascotas
  Como dueño de una tienda de mascotas
  Quiero poder gestionar mi inventario y vender mascotas
  Para poder llevar un registro adecuado de las operaciones.

  Scenario: Añadir mascotas al inventario
    Given que tengo una tienda de mascotas
    When añado una mascota llamada "Fido", tipo "Perro", con un precio de 100
    Then debería ver "Fido" en el inventario

  Scenario: Visualizar el inventario de mascotas
    Given que tengo una tienda de mascotas con varias mascotas
    When visualizo el inventario
    Then debería ver todas las mascotas disponibles

  Scenario: Comprar una mascota
    Given que tengo una tienda con "Fido" disponible
    When compro a "Fido"
    Then el inventario de "Fido" debería reducirse en 1
    And debería recibir un recibo por la compra

  Scenario: Comprar una mascota fuera de stock
    Given que "Fido" ya no está en inventario
    When intento comprar a "Fido"
    Then debería ver un mensaje de error "Mascota no disponible"

Con estos escenarios, hemos descrito las funcionalidades clave de la tienda: añadir mascotas, visualizar el inventario, realizar compras y gestionar los errores cuando no hay stock.

Paso 2: Escribir Pruebas con TDD

Ahora que hemos definido el comportamiento esperado, pasamos a escribir las pruebas en JUnit para asegurarnos de que cada funcionalidad está cubierta.


import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class TiendaMascotasTest {

    private TiendaMascotas tienda;

    @Before
    public void setup() {
        tienda = new TiendaMascotas();
    }

    @Test
    public void agregarMascotaAlInventario() {
        tienda.agregarMascota("Fido", "Perro", 100);
        assertTrue(tienda.inventarioContiene("Fido"));
    }

    @Test
    public void visualizarInventario() {
        tienda.agregarMascota("Fido", "Perro", 100);
        tienda.agregarMascota("Miau", "Gato", 80);
        assertEquals(2, tienda.obtenerInventario().size());
    }

    @Test
    public void comprarMascotaReduceInventario() {
        tienda.agregarMascota("Fido", "Perro", 100);
        tienda.comprarMascota("Fido");
        assertFalse(tienda.inventarioContiene("Fido"));
    }

    @Test
    public void reciboTrasCompraDeMascota() {
        tienda.agregarMascota("Fido", "Perro", 100);
        String recibo = tienda.comprarMascota("Fido");
        assertEquals("Has comprado a Fido por 100 euros.", recibo);
    }

    @Test(expected = RuntimeException.class)
    public void comprarMascotaFueraDeStockLanzaExcepcion() {
        tienda.comprarMascota("Fido");
    }
}

Estas pruebas cubren los principales casos de uso de nuestra tienda de mascotas. Antes de implementar cualquier funcionalidad, ya tenemos claro qué es lo que queremos verificar.

Paso 3: Implementar la Tienda de Mascotas

Ahora que hemos definido las pruebas, podemos pasar a implementar el código que hará que la tienda funcione correctamente:


import java.util.HashMap;
import java.util.Map;

public class TiendaMascotas {

    private Map<String, Mascota> inventario;

    public TiendaMascotas() {
        inventario = new HashMap<>();
    }

    public void agregarMascota(String nombre, String tipo, int precio) {
        Mascota mascota = new Mascota(nombre, tipo, precio);
        inventario.put(nombre, mascota);
    }

    public boolean inventarioContiene(String nombre) {
        return inventario.containsKey(nombre);
    }

    public Map<String, Mascota> obtenerInventario() {
        return inventario;
    }

    public String comprarMascota(String nombre) {
        if (!inventario.containsKey(nombre)) {
            throw new RuntimeException("Mascota no disponible");
        }
        Mascota mascota = inventario.remove(nombre);
        return "Has comprado a " + mascota.getNombre() + " por " + mascota.getPrecio() + " euros.";
    }
}

Con este código, hemos implementado todas las funcionalidades necesarias para que la tienda de mascotas funcione. El inventario es gestionado con un mapa (HashMap), y cada operación que realizamos modifica el estado del inventario.

Paso 4: Comprobar el Resultado

Finalmente, ejecuta las pruebas que hemos escrito en JUnit. Si todas las pruebas pasan, ¡enhorabuena! Has completado con éxito el segundo desafío. Tu tienda de mascotas está lista para funcionar, y lo mejor es que has seguido los principios de BDD y TDD para garantizar que el código cumple con los requisitos y es de calidad.

¡Prepárate para el próximo desafío!

Desafío 3: El Generador de Contraseñas Seguras

¡Enhorabuena por llegar al tercer desafío! Ahora nos adentramos en algo muy útil: un generador de contraseñas seguras. Este generador deberá seguir ciertas reglas de seguridad para garantizar que las contraseñas que crea sean robustas y difíciles de adivinar. Utilizaremos BDD para definir esas reglas de seguridad y TDD para asegurarnos de que la funcionalidad cumple con los requisitos.

Descripción del Desafío

El objetivo de este desafío es desarrollar un generador de contraseñas seguras. Debe cumplir con ciertas reglas para garantizar la seguridad de las contraseñas generadas:

  • La contraseña debe tener al menos 8 caracteres.
  • Debe contener una combinación de letras mayúsculas, minúsculas, números y caracteres especiales.
  • No debe generar la misma contraseña más de una vez.
  • El usuario puede especificar la longitud deseada de la contraseña.

Definiremos estas reglas utilizando BDD y luego aplicaremos TDD para desarrollar las pruebas que aseguren el correcto funcionamiento del generador.

Reglas del Juego

A continuación, las reglas y criterios que guiarán la implementación del generador de contraseñas seguras:

  1. El generador debe permitir al usuario definir la longitud de la contraseña (mínimo 8 caracteres).
  2. La contraseña generada debe contener al menos una letra mayúscula, una letra minúscula, un número y un carácter especial.
  3. Las contraseñas generadas deben ser únicas, es decir, no puede repetirse ninguna.
  4. El proceso debe pasar todas las pruebas antes de considerarse completo.

Criterio de éxito: El desafío se completará con éxito cuando el generador de contraseñas cumpla con todas las reglas de seguridad y las pruebas unitarias creadas con TDD pasen sin errores.

Solución y Código de Ejemplo

Paso 1: Definir el Comportamiento con BDD

Primero, como es habitual, definimos los escenarios utilizando Cucumber para describir el comportamiento esperado del generador de contraseñas seguras:


Feature: Generación de contraseñas seguras
  Como usuario
  Quiero generar contraseñas seguras
  Para proteger mis cuentas en línea.

  Scenario: Generar una contraseña con las características mínimas
    Given que quiero una contraseña segura
    When genero una contraseña de 8 caracteres
    Then la contraseña debería contener al menos una letra mayúscula, una letra minúscula, un número y un carácter especial

  Scenario: Definir la longitud de la contraseña
    Given que quiero una contraseña segura
    When especifico que la contraseña debe tener 12 caracteres
    Then la contraseña generada debería tener exactamente 12 caracteres

  Scenario: Generar contraseñas únicas
    Given que quiero generar varias contraseñas
    When genero 10 contraseñas
    Then todas las contraseñas deberían ser únicas

Estos tres escenarios nos permiten cubrir las funcionalidades básicas de nuestro generador de contraseñas: cumplimiento de los requisitos de seguridad, control de la longitud de la contraseña y garantía de que no se repitan contraseñas.

Paso 2: Escribir Pruebas con TDD

A continuación, implementamos las pruebas unitarias que verificarán el comportamiento del generador. Utilizaremos JUnit para ello.


import org.junit.Test;
import static org.junit.Assert.*;

public class GeneradorContrasenasTest {

    private GeneradorContrasenas generador = new GeneradorContrasenas();

    @Test
    public void generarContrasenaCumpleConReglasDeSeguridad() {
        String contrasena = generador.generar(8);
        assertTrue(contrasena.length() >= 8);
        assertTrue(contrasena.matches(".*[A-Z].*"));  // Al menos una mayúscula
        assertTrue(contrasena.matches(".*[a-z].*"));  // Al menos una minúscula
        assertTrue(contrasena.matches(".*\\d.*"));    // Al menos un número
        assertTrue(contrasena.matches(".*[!@#\\$%\\^&\\*].*"));  // Al menos un carácter especial
    }

    @Test
    public void contrasenaTieneLongitudEspecificada() {
        String contrasena = generador.generar(12);
        assertEquals(12, contrasena.length());
    }

    @Test
    public void generarContrasenasUnicas() {
        Set<String> contrasenas = new HashSet<>();
        for (int i = 0; i < 10; i++) {
            contrasenas.add(generador.generar(10));
        }
        assertEquals(10, contrasenas.size());
    }
}

Estas pruebas aseguran que las contraseñas cumplen con las reglas de seguridad, que podemos generar contraseñas de una longitud específica y que cada contraseña es única.

Paso 3: Implementar el Generador de Contraseñas

Ahora que hemos definido las pruebas, pasamos a implementar el código para el generador de contraseñas:


import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Set;

public class GeneradorContrasenas {

    private static final String MAYUSCULAS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String MINUSCULAS = "abcdefghijklmnopqrstuvwxyz";
    private static final String NUMEROS = "0123456789";
    private static final String CARACTERES_ESPECIALES = "!@#$%^&*";
    private static final String TODOS_LOS_CARACTERES = MAYUSCULAS + MINUSCULAS + NUMEROS + CARACTERES_ESPECIALES;

    private SecureRandom random = new SecureRandom();
    private Set<String> contrasenasGeneradas = new HashSet<>();

    public String generar(int longitud) {
        if (longitud < 8) {
            throw new IllegalArgumentException("La contraseña debe tener al menos 8 caracteres.");
        }

        StringBuilder contrasena = new StringBuilder(longitud);

        // Aseguramos que la contraseña contiene al menos una mayúscula, minúscula, número y carácter especial
        contrasena.append(MAYUSCULAS.charAt(random.nextInt(MAYUSCULAS.length())));
        contrasena.append(MINUSCULAS.charAt(random.nextInt(MINUSCULAS.length())));
        contrasena.append(NUMEROS.charAt(random.nextInt(NUMEROS.length())));
        contrasena.append(CARACTERES_ESPECIALES.charAt(random.nextInt(CARACTERES_ESPECIALES.length())));

        // Rellenamos el resto de la contraseña con caracteres aleatorios
        for (int i = 4; i < longitud; i++) {
            contrasena.append(TODOS_LOS_CARACTERES.charAt(random.nextInt(TODOS_LOS_CARACTERES.length())));
        }

        // Barajamos los caracteres para evitar que los primeros 4 sigan el mismo patrón
        return barajar(contrasena.toString());
    }

    private String barajar(String contrasena) {
        List<Character> caracteres = contrasena.chars().mapToObj(c -> (char) c).collect(Collectors.toList());
        Collections.shuffle(caracteres);
        StringBuilder contrasenaBarajada = new StringBuilder();
        for (char c : caracteres) {
            contrasenaBarajada.append(c);
        }
        return contrasenaBarajada.toString();
    }
}

Este código genera contraseñas seguras que cumplen con los requisitos de seguridad, asegurando que cada contraseña tenga al menos una mayúscula, una minúscula, un número y un carácter especial, además de barajar los caracteres para mayor seguridad.

Paso 4: Comprobar el Resultado

Ejecuta las pruebas unitarias que hemos escrito anteriormente. Si todas las pruebas se ejecutan sin errores, ¡has completado el desafío con éxito! Tu generador de contraseñas seguras está listo para usar y cumple con los requisitos de seguridad definidos con BDD y verificados con TDD.

¡Felicidades! Ahora puedes generar contraseñas seguras para proteger cualquier cuenta en línea. ¡Adelante con el próximo desafío!

Desafío 4: El Rastreador de Actividades

¡Bienvenido al cuarto desafío! En este desafío construiremos una aplicación para rastrear actividades diarias. La idea es poder registrar las tareas o actividades que realizamos a lo largo del día y llevar un seguimiento de ellas. Vamos a definir el comportamiento de la aplicación con BDD y validar su funcionalidad con TDD.

Descripción del Desafío

Este desafío consiste en desarrollar una aplicación que permita a los usuarios:

  • Registrar actividades con nombre, duración y fecha.
  • Editar y eliminar actividades.
  • Visualizar un resumen diario de las actividades realizadas.

El enfoque será definir primero las historias de usuario y criterios de aceptación usando BDD, y luego implementar las pruebas y el código con TDD para garantizar que la aplicación funcione correctamente.

Reglas del Juego

Aquí están las reglas para completar el desafío de manera exitosa:

  1. La aplicación debe permitir al usuario agregar una actividad con nombre, duración (en minutos) y fecha.
  2. Debe ser posible editar o eliminar actividades.
  3. El usuario debe poder ver un resumen de todas las actividades realizadas en un día, con el total de tiempo dedicado a cada una.
  4. Las pruebas deben cubrir la funcionalidad completa antes de dar por terminado el desafío.

Criterio de éxito: El desafío se considera completado cuando la aplicación funciona correctamente según los requisitos y todas las pruebas unitarias pasan sin errores.

Solución y Código de Ejemplo

Paso 1: Definir el Comportamiento con BDD

Comenzamos definiendo el comportamiento esperado de la aplicación utilizando Cucumber para escribir nuestras historias de usuario.


Feature: Rastreo de actividades diarias
  Como usuario
  Quiero poder registrar, editar y eliminar actividades diarias
  Para llevar un control de cómo uso mi tiempo.

  Scenario: Registrar una nueva actividad
    Given que estoy en la página de registro de actividades
    When añado una actividad con nombre "Leer", duración de 30 minutos y fecha "2024-09-10"
    Then la actividad debería aparecer en mi lista de actividades

  Scenario: Editar una actividad existente
    Given que tengo una actividad llamada "Leer" en mi lista de actividades
    When edito la duración de la actividad a 45 minutos
    Then la lista de actividades debería reflejar la nueva duración

  Scenario: Eliminar una actividad
    Given que tengo una actividad llamada "Leer" en mi lista de actividades
    When elimino la actividad
    Then la actividad debería desaparecer de mi lista

  Scenario: Ver el resumen diario
    Given que he registrado varias actividades para el día "2024-09-10"
    When consulto el resumen diario
    Then debería ver el total de tiempo dedicado a cada actividad

Estas historias de usuario cubren las funcionalidades clave de la aplicación: agregar, editar, eliminar actividades y ver un resumen diario de las actividades realizadas.

Paso 2: Escribir Pruebas con TDD

Ahora vamos a escribir las pruebas unitarias utilizando JUnit para asegurarnos de que la funcionalidad de nuestra aplicación está cubierta.


import org.junit.Test;
import static org.junit.Assert.*;
import java.util.List;

public class RastreadorActividadesTest {

    private RastreadorActividades rastreador = new RastreadorActividades();

    @Test
    public void registrarNuevaActividad() {
        rastreador.registrarActividad("Leer", 30, "2024-09-10");
        List<Actividad> actividades = rastreador.obtenerActividades();
        assertEquals(1, actividades.size());
        assertEquals("Leer", actividades.get(0).getNombre());
        assertEquals(30, actividades.get(0).getDuracion());
    }

    @Test
    public void editarActividad() {
        rastreador.registrarActividad("Leer", 30, "2024-09-10");
        rastreador.editarActividad("Leer", 45);
        Actividad actividad = rastreador.obtenerActividadPorNombre("Leer");
        assertEquals(45, actividad.getDuracion());
    }

    @Test
    public void eliminarActividad() {
        rastreador.registrarActividad("Leer", 30, "2024-09-10");
        rastreador.eliminarActividad("Leer");
        List<Actividad> actividades = rastreador.obtenerActividades();
        assertEquals(0, actividades.size());
    }

    @Test
    public void verResumenDiario() {
        rastreador.registrarActividad("Leer", 30, "2024-09-10");
        rastreador.registrarActividad("Ejercicio", 60, "2024-09-10");
        String resumen = rastreador.obtenerResumenDiario("2024-09-10");
        assertTrue(resumen.contains("Leer: 30 minutos"));
        assertTrue(resumen.contains("Ejercicio: 60 minutos"));
    }
}

Estas pruebas cubren las funcionalidades clave: registrar una nueva actividad, editarla, eliminarla y ver un resumen diario.

Paso 3: Implementar el Rastreador de Actividades

Ahora que tenemos nuestras pruebas, es hora de implementar la funcionalidad del rastreador de actividades:


import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class RastreadorActividades {

    private List<Actividad> actividades = new ArrayList<>();

    public void registrarActividad(String nombre, int duracion, String fecha) {
        actividades.add(new Actividad(nombre, duracion, fecha));
    }

    public List<Actividad> obtenerActividades() {
        return actividades;
    }

    public Actividad obtenerActividadPorNombre(String nombre) {
        return actividades.stream()
                          .filter(a -> a.getNombre().equals(nombre))
                          .findFirst()
                          .orElse(null);
    }

    public void editarActividad(String nombre, int nuevaDuracion) {
        Actividad actividad = obtenerActividadPorNombre(nombre);
        if (actividad != null) {
            actividad.setDuracion(nuevaDuracion);
        }
    }

    public void eliminarActividad(String nombre) {
        actividades.removeIf(a -> a.getNombre().equals(nombre));
    }

    public String obtenerResumenDiario(String fecha) {
        List<Actividad> actividadesDelDia = actividades.stream()
                                                .filter(a -> a.getFecha().equals(fecha))
                                                .collect(Collectors.toList());
        StringBuilder resumen = new StringBuilder();
        for (Actividad actividad : actividadesDelDia) {
            resumen.append(actividad.getNombre())
                   .append(": ")
                   .append(actividad.getDuracion())
                   .append(" minutos\n");
        }
        return resumen.toString();
    }
}

Este código nos permite registrar actividades, editarlas, eliminarlas y ver un resumen de las actividades diarias.

Paso 4: Comprobar el Resultado

Por último, ejecuta las pruebas unitarias que escribimos en el paso 2. Si todas las pruebas pasan, ¡has completado el desafío con éxito! Tu rastreador de actividades ya está listo para ayudar a los usuarios a organizar su tiempo de manera eficiente.

¡Excelente trabajo! Este desafío te ha permitido aplicar BDD y TDD para construir una aplicación útil y funcional que lleva el control de las actividades diarias.

Desafío 5: La Aplicación de Conversión de Monedas

¡Bienvenido al quinto desafío! En este reto, vamos a crear una aplicación de conversión de monedas que permita convertir entre diferentes divisas. Utilizaremos BDD para definir las reglas de conversión y TDD para garantizar que la aplicación funcione de manera correcta y precisa.

Descripción del Desafío

Este desafío consiste en desarrollar una aplicación que permita a los usuarios convertir dinero entre varias monedas (por ejemplo, de euros a dólares, de libras a yenes, etc.). El valor de la conversión dependerá de las tasas de cambio que se proporcionen o que el usuario introduzca manualmente.

El objetivo es practicar la metodología de BDD para definir los criterios de aceptación de las conversiones y luego usar TDD para implementar la funcionalidad, asegurando que las pruebas cubran todos los casos de uso posibles.

Reglas del Juego

Las reglas para completar este desafío con éxito son las siguientes:

  1. La aplicación debe permitir convertir entre al menos tres monedas (por ejemplo, euros, dólares y yenes).
  2. El usuario debe poder seleccionar la moneda de origen, la moneda de destino y la cantidad a convertir.
  3. El tipo de cambio entre las monedas debe ser configurable o cargado de un servicio externo simulado.
  4. El resultado de la conversión debe mostrarse claramente y debe ser preciso.
  5. La aplicación debe estar cubierta por pruebas unitarias que validen la conversión entre las diferentes monedas.

Criterios de éxito: El desafío se considerará completado cuando la aplicación realice correctamente las conversiones de monedas y todas las pruebas unitarias pasen satisfactoriamente.

Solución y Código de Ejemplo

Paso 1: Definir el Comportamiento con BDD

Empezaremos definiendo el comportamiento esperado de la aplicación utilizando Cucumber para escribir nuestras historias de usuario:


Feature: Conversión de monedas
  Como usuario
  Quiero convertir dinero entre diferentes monedas
  Para saber cuánto vale mi dinero en otra divisa.

  Scenario: Convertir de euros a dólares
    Given que tengo una tasa de cambio de 1 euro por 1.2 dólares
    When convierto 100 euros a dólares
    Then debería obtener 120 dólares

  Scenario: Convertir de dólares a yenes
    Given que tengo una tasa de cambio de 1 dólar por 110 yenes
    When convierto 50 dólares a yenes
    Then debería obtener 5500 yenes

  Scenario: Cambiar la tasa de cambio manualmente
    Given que la tasa de cambio entre euros y libras es 0.85
    When actualizo la tasa de cambio a 0.9
    Then la nueva tasa de cambio debe ser utilizada en las futuras conversiones

Estas historias de usuario cubren los casos más comunes: conversión entre monedas con diferentes tasas de cambio y la posibilidad de actualizar dichas tasas manualmente.

Paso 2: Escribir Pruebas con TDD

Con las historias de usuario claras, ahora pasamos a escribir las pruebas unitarias con JUnit para asegurar que nuestra aplicación funcione correctamente.


import org.junit.Test;
import static org.junit.Assert.*;

public class ConversorMonedasTest {

    private ConversorMonedas conversor = new ConversorMonedas();

    @Test
    public void convertirEurosADolares() {
        conversor.establecerTasaCambio("EUR", "USD", 1.2);
        double resultado = conversor.convertir("EUR", "USD", 100);
        assertEquals(120.0, resultado, 0.001);
    }

    @Test
    public void convertirDolaresAYenes() {
        conversor.establecerTasaCambio("USD", "JPY", 110);
        double resultado = conversor.convertir("USD", "JPY", 50);
        assertEquals(5500, resultado, 0.001);
    }

    @Test
    public void cambiarTasaDeCambio() {
        conversor.establecerTasaCambio("EUR", "GBP", 0.85);
        conversor.establecerTasaCambio("EUR", "GBP", 0.9);
        double resultado = conversor.convertir("EUR", "GBP", 100);
        assertEquals(90, resultado, 0.001);
    }
}

Estas pruebas nos aseguran que las conversiones se realizan de manera correcta para los diferentes escenarios definidos.

Paso 3: Implementar la Lógica del Conversor de Monedas

Ahora que tenemos nuestras pruebas, podemos proceder a implementar el código para que las conversiones funcionen:


import java.util.HashMap;
import java.util.Map;

public class ConversorMonedas {

    private Map<String, Double> tasasDeCambio = new HashMap<>();

    public void establecerTasaCambio(String monedaOrigen, String monedaDestino, double tasa) {
        tasasDeCambio.put(monedaOrigen + "_" + monedaDestino, tasa);
    }

    public double convertir(String monedaOrigen, String monedaDestino, double cantidad) {
        String clave = monedaOrigen + "_" + monedaDestino;
        if (tasasDeCambio.containsKey(clave)) {
            return cantidad * tasasDeCambio.get(clave);
        } else {
            throw new IllegalArgumentException("Tasa de cambio no encontrada para " + monedaOrigen + " a " + monedaDestino);
        }
    }
}

Este código permite convertir entre diferentes monedas utilizando las tasas de cambio que se configuran previamente.

Paso 4: Ejecutar las Pruebas

Por último, ejecuta las pruebas unitarias para asegurarte de que todo funciona correctamente. Si las pruebas pasan, habrás completado el desafío con éxito. ¡Tu aplicación de conversión de monedas está lista para ser utilizada!

Este desafío no solo te ha permitido practicar BDD y TDD, sino que también te ha mostrado cómo crear una herramienta útil y funcional para convertir entre diferentes divisas.

Conclusiones Juegos y Desafíos de Código: Practica BDD y TDD de Forma Divertida

A lo largo de estos desafíos, hemos explorado la importancia de BDD y TDD como herramientas fundamentales para el desarrollo de software de alta calidad. A través de juegos interactivos y ejemplos prácticos, hemos aprendido a:

  • Definir requisitos claros mediante historias de usuario y criterios de aceptación con BDD, asegurando que todo el equipo esté alineado desde el inicio del desarrollo.
  • Escribir pruebas antes de implementar el código, aplicando TDD para validar la funcionalidad paso a paso, garantizando que cada pieza del sistema funcione como se espera.
  • Desarrollar soluciones eficientes a problemas complejos utilizando un ciclo de retroalimentación constante entre pruebas, código y refactorización, mejorando continuamente la calidad del código.

Estos desafíos también te han mostrado cómo aplicar BDD y TDD de manera práctica en una variedad de contextos, desde simples aplicaciones como un generador de contraseñas hasta un conversor de monedas o un rastreador de actividades. Lo más valioso es que ahora puedes trasladar estos conceptos a proyectos reales, donde el uso de pruebas y especificaciones definidas desde el principio puede marcar una gran diferencia en la calidad y mantenibilidad de tu código.

Recuerda que la práctica hace al maestro. El desarrollo basado en pruebas requiere tiempo y dedicación, pero a largo plazo, las ventajas en términos de detección temprana de errores, agilidad en el desarrollo y confianza en la estabilidad del sistema son enormes.

Siguientes Pasos y Recursos Adicionales

Ahora que tienes una sólida base en BDD y TDD, ¿cuáles son los siguientes pasos para continuar tu aprendizaje?

Seguir Practicando

La mejor manera de seguir mejorando es practicar constantemente. Aquí tienes algunas ideas para continuar:

  • Contribuye a proyectos open-source: Busca proyectos en GitHub donde puedas aplicar BDD y TDD. Ver cómo otros desarrolladores utilizan estas técnicas te dará una visión más amplia.
  • Crea tus propios desafíos: Define retos similares a los que hemos cubierto en este artículo y pon a prueba tus habilidades. Puedes explorar nuevos dominios como aplicaciones móviles o APIs.
  • Refactoriza proyectos existentes: Si tienes proyectos personales que no utilizan pruebas, intenta integrarlas para ver cómo mejora la estabilidad y el mantenimiento del código.

Recursos Recomendados

Además, te recomiendo estos recursos para profundizar en BDD y TDD:

  • Cucumber: El sitio oficial de Cucumber, una herramienta fundamental para BDD.
  • JUnit: La documentación oficial de JUnit, que te permitirá explorar más opciones para escribir pruebas en Java.
  • Agile Alliance – TDD: Una excelente fuente para entender el contexto ágil de TDD y cómo aplicarlo en diferentes entornos.
  • Uncle Bob – Clean Code: El canal de YouTube de Robert C. Martin, uno de los gurús en TDD y buenas prácticas de código.

¡Ahora es tu turno! ¿Estás listo para aplicar lo que has aprendido en proyectos reales?

5 1 voto
Puntúa la entrada
Suscribir
Notificar de
guest
El usuario da permiso para entrar en nuestro boletin
0 Comentarios
Más antiguo
Más nuevo Más Votado
Comentarios en línea
Ver todos los comentarios
ENCUENTRA TU CURSO

Solo cursos gratuitos

¡Cuéntanos qué necesitas!

Quiero recibir información y novedades de IMPULSO_06

¡Termina tu preinscripción!

Quiero recibir información y novedades de IMPULSO_06