Salta el contingut
 

Exemple: Proves unitàries de pedra, paper i tisores

Autor: Joan Puigcerver Ibáñez

Correu electrònic: j.puigcerveribanez@edu.gva.es

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Proves unitàries

Les proves unitàries són una tècnica de verificació de programari que s'utilitza per assegurar que cada part ("unitat") del programa funciona correctament. Aquesta tècnica es basa en la idea de dividir el programa en parts més xicotetes i escriure proves per a cada part per comprovar que totes elles funcionen correctament.

Això és útil perquè, quan es produeixen canvis en un programa, és més fàcil determinar què ha anat malament si es poden comprovar les parts individuals del programa. Això també pot ajudar a detectar errors més ràpidament i a prevenir la introducció de nous errors durant el manteniment del programa. Java té diverses eines per escriure i executar les proves.

Creació de proves

ud4.examples

Anem a crear unes proves unitàries per comprovar que el programa DebugRockPaperScissors funciona correctament.

Per poder provar aquest codi, s'ha creat una nova versió del programa que incorpora el mètode int guanya(String jugador1, String jugador2), que determina quin jugador ha guanyat la partida:

DebugRockPaperScissors.java
package ud4.examples;

import java.util.Locale;
import java.util.Scanner;

public class DebugRockPaperScissors {

    /**
     * Determina quin jugador ha guanyat la partida de pedra paper i tisores.
     * <p>
     * Aquest mètode retorna 0 si hi ha hagut un empat, 1 si el jugador1 ha guanyat la partida,
     * i 2 si el jugador2 ha guanyat.
     *
     * @param jugador1 Jugada del jugador1 (pedra, paper o tisores)
     * @param jugador2 Jugada del jugador1 (pedra, paper o tisores)
     * @return 0 si hi ha un empat; 1 si guanya jugador1; 2 si guanya jugador 2.
     */
    public static int guanya(String jugador1, String jugador2){
        if(jugador1.equals(jugador2))
            return 0;
        else if (jugador1.equals("paper")) {
            return jugador2.equals("pedra") ? 2 : 1;
        } else if (jugador1.equals("pedra")) {
            return jugador2.equals("paper") ? 1 : 2;
        } else {
            return jugador2.equals("paper") ? 1 : 2;
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in).useLocale(Locale.US);
        System.out.print("Introdueix l'elecció del jugador 2 (pedra/paper/tisores): ");
        String p1 = in.nextLine();
        System.out.print("Introdueix l'elecció del jugador 2 (pedra/paper/tisores): ");
        String p2 = in.nextLine();

        int guanyador = guanya(p1, p2);
        if (guanyador == 0)
            System.out.println("Empat");
        else
            System.out.printf("Guanya el jugador %d\n", guanyador);
    }
}

Anem a comprovar si el mètode està ben implementat utilitzant proves unitàries:

  1. Situat sobre el nom de la classe DebugRockPaperScissors, prem Alt+Ins i selecciona Test.

    També pots prémer Alt+Enter o clicar el botó dret i selecciona Show Context Actions. Des del menú, selecciona Create Test.

    Crear prova mitjançant el menú contextual

    Figura 1. Crear prova mitjançant el menú contextual

  2. Selecciona els mètodes que vols provar en el diàleg i prem OK.

    Configuració de la prova

    Figura 2. Configuració de la prova

  3. L'acció anterior crearà un nou fixer en src/test/java, la carpeta designada on guardar les proves del projecte.

    El nou fitxer es troba en la mateixa estructura de paquets que el codi font: ud5.examples.

    Fitxer de prova creat

    Figura 3. Fitxer de prova creat

  4. Dissenyem proves per comprovar si el mètode guanya() funciona correctament en tots els casos.

    Jugador 1 Jugador 2 Resultat
    Pedra Pedra Empat
    Pedra Paper Jugador 2 guanya
    Pedra Tisores Jugador 1 guanya
    Paper Pedra Jugador 1 guanya
    Paper Paper Empat
    Paper Tisores Jugador 2 guanya
    Tisores Pedra Jugador 2 guanya
    Tisores Paper Jugador 1 guanya
    Tisores Tisores Empat
  5. Modifiquem el fitxer amb les proves per incloure els casos anteriors. S'han organitzat les proves en classes internes @Nested per millorar la organització de les proves.

    DebugRockPaperScissorsTest.java
    package ud4.examples;
    
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Nested;
    import org.junit.jupiter.api.Test;
    
    import static org.junit.jupiter.api.Assertions.*;
    
    class DebugRockPaperScissorsTest {
    
        @Nested
        class Empat {
    
            @Test
            @DisplayName("Empat: Pedra vs Pedra")
            void testEmpatPedraPedra() {
                int expected = 0;
                int actual = DebugRockPaperScissors.guanya("pedra", "pedra");
    
                assertEquals(expected, actual);
            }
    
            @Test
            @DisplayName("Empat: Paper vs Paper")
            void testEmpatPaperPaper() {
                int expected = 0;
                int actual = DebugRockPaperScissors.guanya("paper", "paper");
    
                assertEquals(expected, actual);
            }
    
            @Test
            @DisplayName("Empat: Tisores vs Tisora")
            void testEmpatTisoresTisora() {
                int expected = 0;
                int actual = DebugRockPaperScissors.guanya("tisores", "tisores");
    
                assertEquals(expected, actual);
            }
        }
    
        @Nested
        class Jugador1 {
    
            @Test
            @DisplayName("Jugador 1 guanya: Pedra vs Tisores")
            void testJugador1GuanyaPedraTisores() {
                int expected = 1;
                int actual = DebugRockPaperScissors.guanya("pedra", "tisores");
    
                assertEquals(expected, actual);
            }
    
            @Test
            @DisplayName("Jugador 1 guanya: Paper vs Pedra")
            void testJugador1GuanyaPaperPedra() {
                int expected = 1;
                int actual = DebugRockPaperScissors.guanya("paper", "pedra");
    
                assertEquals(expected, actual);
            }
    
            @Test
            @DisplayName("Jugador 1 guanya: Tisores vs Paper")
            void testJugador1GuanyaTisoresPaper() {
                int expected = 1;
                int actual = DebugRockPaperScissors.guanya("tisores", "paper");
    
                assertEquals(expected, actual);
            }
        }
    
        @Nested
        class Jugador2 {
    
            @Test
            @DisplayName("Jugador 2 guanya: Tisores vs Pedra")
            void testJugador2GuanyaTisoresPedra() {
                int expected = 2;
                int actual = DebugRockPaperScissors.guanya("tisores", "pedra");
    
                assertEquals(expected, actual);
            }
    
            @Test
            @DisplayName("Jugador 2 guanya: Pedra vs Paper")
            void testJugador2GuanyaPedraPaper() {
                int expected = 2;
                int actual = DebugRockPaperScissors.guanya("pedra", "paper");
    
                assertEquals(expected, actual);
            }
    
            @Test
            @DisplayName("Jugador 2 guanya: Paper vs Tisores")
            void testJugador2GuanyaPaperTisores() {
                int expected = 2;
                int actual = DebugRockPaperScissors.guanya("paper", "tisores");
    
                assertEquals(expected, actual);
            }
        }
    }
    

Execució de les proves

Una vegada s'han implementat les proves, anem a executar-les per veure si el mètode int guanya(String jugador1, String jugador2) funciona correctament.

Per executar-les, s'ha de clicar el botó Run.

Execució de les proves

Figura 4. Execució de les proves

Una vegada executats, podem consultar els resultats:

Resultats de les proves

Figura 5. Resultats de les proves

Es poden observar els resultats de cada prova per separat. En aquest cas han fallat algunes de les proves, per tant, que caldrà revisar els errors i corregir el codi.