En aquest tema, aprendrem sobre les tècniques de proves i depuració en C++. Aquestes habilitats són essencials per assegurar que el teu codi funcioni correctament i sigui robust. Explorarem diferents tipus de proves, eines de depuració i estratègies per identificar i corregir errors.

  1. Tipus de Proves

1.1 Proves Unitàries

Les proves unitàries són proves que verifiquen el funcionament de components individuals del codi, com ara funcions o mètodes. Aquestes proves són crucials per assegurar que cada part del codi funcioni correctament de manera independent.

Exemple:

#include <cassert>

// Funció a provar
int suma(int a, int b) {
    return a + b;
}

int main() {
    // Prova unitària
    assert(suma(2, 3) == 5);
    assert(suma(-1, 1) == 0);
    assert(suma(0, 0) == 0);
    return 0;
}

Explicació:

  • Utilitzem assert per verificar que la funció suma retorna els resultats esperats.
  • Si alguna de les afirmacions falla, el programa es tancarà i indicarà l'error.

1.2 Proves d'Integració

Les proves d'integració verifiquen que diferents components del sistema funcionin correctament quan es combinen. Aquestes proves són importants per assegurar que les interaccions entre diferents parts del codi no causin problemes.

Exemple:

#include <cassert>
#include <string>

// Funcions a provar
std::string saluda(const std::string& nom) {
    return "Hola, " + nom + "!";
}

int main() {
    // Prova d'integració
    std::string resultat = saluda("Anna");
    assert(resultat == "Hola, Anna!");
    return 0;
}

Explicació:

  • Verifiquem que la funció saluda funcioni correctament quan es combina amb una cadena de text.

1.3 Proves de Sistema

Les proves de sistema verifiquen el sistema complet per assegurar que compleixi amb els requisits especificats. Aquestes proves es realitzen en un entorn que simula l'ús real del sistema.

1.4 Proves de Regressió

Les proves de regressió asseguren que els canvis en el codi no introdueixin nous errors en les parts ja provades. Aquestes proves es realitzen després de cada canvi significatiu en el codi.

  1. Eines de Depuració

2.1 GDB (GNU Debugger)

GDB és una eina de depuració popular per a programes escrits en C i C++. Permet als desenvolupadors executar el codi pas a pas, inspeccionar variables i memòria, i identificar la causa dels errors.

Comandes Bàsiques de GDB:

  • gdb ./programa: Inicia GDB amb el programa especificat.
  • break main: Estableix un punt de ruptura a la funció main.
  • run: Executa el programa fins al punt de ruptura.
  • next: Executa la següent línia de codi.
  • print variable: Mostra el valor de la variable especificada.
  • continue: Continua l'execució fins al següent punt de ruptura.

2.2 Valgrind

Valgrind és una eina per detectar errors de memòria, com ara fuites de memòria i accessos no vàlids a la memòria.

Exemple d'ús:

valgrind --leak-check=full ./programa

Explicació:

  • --leak-check=full activa la verificació completa de fuites de memòria.
  • ./programa és el programa a depurar.

  1. Estratègies de Depuració

3.1 Utilitzar Missatges de Depuració

Afegir missatges de depuració al codi pot ajudar a identificar on es produeixen els errors. Utilitza std::cout per imprimir missatges i valors de variables.

Exemple:

#include <iostream>

int divideix(int a, int b) {
    if (b == 0) {
        std::cerr << "Error: Divisió per zero!" << std::endl;
        return 0;
    }
    return a / b;
}

int main() {
    int resultat = divideix(10, 0);
    std::cout << "Resultat: " << resultat << std::endl;
    return 0;
}

Explicació:

  • Utilitzem std::cerr per imprimir missatges d'error.
  • std::cout s'utilitza per imprimir el resultat.

3.2 Revisar el Codi Pas a Pas

Revisar el codi pas a pas pot ajudar a identificar on es produeixen els errors. Utilitza un depurador com GDB per executar el codi línia per línia.

3.3 Verificar Assumptions

Assegura't que les teves assumpcions sobre el codi siguin correctes. Utilitza assert per verificar que les condicions esperades es compleixin.

Exemple:

#include <cassert>

int factorial(int n) {
    assert(n >= 0); // Verifica que n sigui no negatiu
    if (n == 0) return 1;
    return n * factorial(n - 1);
}

Explicació:

  • Utilitzem assert per assegurar-nos que n sigui no negatiu abans de calcular el factorial.

Exercicis Pràctics

Exercici 1: Prova Unitària

Escriu una prova unitària per a la funció següent que calcula el quadrat d'un nombre:

int quadrat(int x) {
    return x * x;
}

Solució:

#include <cassert>

int quadrat(int x) {
    return x * x;
}

int main() {
    assert(quadrat(2) == 4);
    assert(quadrat(-3) == 9);
    assert(quadrat(0) == 0);
    return 0;
}

Exercici 2: Depuració amb GDB

Compila i depura el següent codi amb GDB. Identifica i corregeix l'error:

#include <iostream>

int main() {
    int a = 10;
    int b = 0;
    int c = a / b; // Error: Divisió per zero
    std::cout << "Resultat: " << c << std::endl;
    return 0;
}

Solució:

  • Utilitza GDB per identificar l'error de divisió per zero.
  • Corregeix el codi per evitar la divisió per zero:
#include <iostream>

int main() {
    int a = 10;
    int b = 0;
    if (b != 0) {
        int c = a / b;
        std::cout << "Resultat: " << c << std::endl;
    } else {
        std::cerr << "Error: Divisió per zero!" << std::endl;
    }
    return 0;
}

Conclusió

En aquesta secció, hem après sobre diferents tipus de proves, eines de depuració i estratègies per identificar i corregir errors en el codi C++. Les proves i la depuració són habilitats essencials per a qualsevol programador, ja que asseguren que el codi sigui robust i funcioni correctament. Practica aquestes tècniques regularment per millorar la qualitat del teu codi.

© Copyright 2024. Tots els drets reservats