Introducció al testing

De binefa.com
(dif) ← Versió més antiga | Versió actual (dif) | Versió més nova → (dif)
Salta a la navegació Salta a la cerca

Primera presa de contacte

Codis de testing

  • Per a certificar-se:

ISTQB® Certified Tester Foundation Level

unittest

Codi:

# 00_testing_unittest.py
import unittest

# Funció que volem provar
def suma(a, b):
   return a + b

# Classe de tests
class TestSuma(unittest.TestCase):
   def test_suma_positius(self):
       self.assertEqual(suma(2, 3), 5)
   
   def test_suma_negatius(self):
       self.assertEqual(suma(-1, -1), -2)
   
   def test_suma_mixta(self):
       self.assertEqual(suma(5, -3), 2)
   
   def test_suma_zero(self):
       self.assertEqual(suma(0, 0), 0)

# Executar els tests si s'executa directament aquest fitxer
if __name__ == '__main__':
   unittest.main()

Execució de la prova:

python 00_testing_unittest.py 

Sortida pel terminal:

....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

Forçant un error. Per exemple:

self.assertEqual(suma(-1, -1), -3)

La sortida al terminal seria:

.F..
======================================================================
FAIL: test_suma_negatius (__main__.TestSuma)
----------------------------------------------------------------------
Traceback (most recent call last):
 File "/media/emmagatzematge/curs2024-2025/dam/testing/codis/00_testing_unittest.py", line 14, in test_suma_negatius
   self.assertEqual(suma(-1, -1), -3)
AssertionError: -2 != -3

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (failures=1)

pytest

Heu d'instal·lar pytest

pip install pytest

Si sou a Linux cal afegir la ruta de pytest al PATH. Per exemple, afegint al final de l'arxiu .basrc de la carpeta d'usuari (canvieu jordi pel vostre usuari al sistema):

export PATH=$PATH:/home/jordi/.local/bin

Codi d'exemple:

# 01_testing_pytest.py

# Funció que volem provar
def multiplica(a, b):
   return a * b

# Tests amb pytest (només cal definir funcions que comencin per "test_")
def test_multiplica_positius():
   assert multiplica(3, 4) == 12

def test_multiplica_negatius():
   assert multiplica(-2, -3) == 6

def test_multiplica_mixta():
   assert multiplica(5, -2) == -10 

def test_multiplica_zero():
   assert multiplica(0, 100) == 0

Execució:

pytest 01_testing_pytest.py -v

Sortida pel terminal:

============================= test session starts ==============================
platform linux -- Python 3.9.2, pytest-8.3.5, pluggy-1.5.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /media/emmagatzematge/curs2024-2025/dam/testing/codis
plugins: anyio-3.3.2
collected 4 items                                                              

01_testing_pytest.py::test_multiplica_positius PASSED                    [ 25%]
01_testing_pytest.py::test_multiplica_negatius PASSED                    [ 50%]
01_testing_pytest.py::test_multiplica_mixta PASSED                       [ 75%]
01_testing_pytest.py::test_multiplica_zero PASSED                        [100%]

============================== 4 passed in 0.03s ===============================

Forçant un error. Per exemple:

assert multiplica(5, -2) == -11 

Sortiria pel terminal:

 pytest 01_testing_pytest.py -v
============================= test session starts ==============================
platform linux -- Python 3.9.2, pytest-8.3.5, pluggy-1.5.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /media/emmagatzematge/curs2024-2025/dam/testing/codis
plugins: anyio-3.3.2
collected 4 items                                                               

01_testing_pytest.py::test_multiplica_positius PASSED                    [ 25%]
01_testing_pytest.py::test_multiplica_negatius PASSED                    [ 50%]
01_testing_pytest.py::test_multiplica_mixta FAILED                       [ 75%]
01_testing_pytest.py::test_multiplica_zero PASSED                        [100%]

=================================== FAILURES ===================================
____________________________ test_multiplica_mixta _____________________________

   def test_multiplica_mixta():
>       assert multiplica(5, -2) == -11
E       assert -10 == -11
E        +  where -10 = multiplica(5, -2)

01_testing_pytest.py:15: AssertionError
=========================== short test summary info ============================
FAILED 01_testing_pytest.py::test_multiplica_mixta - assert -10 == -11
========================= 1 failed, 3 passed in 0.10s ==========================

Comprovant múltiples valors. Prova parametritzada

Codi:

# 02_testing_pytest.py

import pytest

def multiplica(a, b):
   return a * b

@pytest.mark.parametrize("a,b,esperat", [
   (3, 4, 12),    # Correcte
   (-2, -3, 5),   # Incorrecte (hauria de ser 6)
   (5, -2, -10),  # Correcte
   (0, 100, 1)    # Incorrecte (hauria de ser 0)
])
def test_multiplica_parametritzada(a, b, esperat):
   assert multiplica(a, b) == esperat

Observeu la sortida al terminal al fer el test:

 pytest 02_testing_pytest.py -v

Exemple amb fixtures (dades de prova reutilitzables) en pytest

Codi:

# 03_testing_fixtures_pytest.py
import pytest

# Definim una fixture (dades de prova)
@pytest.fixture
def llista_nums():
   return [1, 2, 3, 4, 5]

# Test que utilitza la fixture
def test_suma_llista(llista_nums):
   assert sum(llista_nums) == 15

# Test que comprova la longitud
def test_llargada_llista(llista_nums):
   assert len(llista_nums) == 5

Testeig d'excepcions

Codi:

# 04_testing_excepcions_pytest.py
import pytest

def divideix(a, b):
   if b == 0:
       raise ValueError("No es pot dividir per zero!")
   return a / b

def test_divideix():
   assert divideix(10, 2) == 5

def test_divideix_per_zero():
   with pytest.raises(ValueError) as excinfo:
       divideix(5, 0)
   assert "No es pot dividir per zero!" in str(excinfo.value)

Exemples de testing amb QtTest a les Qt en C++

testcalculator

// testcalculator.cpp
#include <QtTest>
#include "calculator.h"

class TestCalculator : public QObject
{
   Q_OBJECT

private slots:
   void testSum()
   {
       Calculator calc;
       QCOMPARE(calc.sum(2, 3), 5);
       QCOMPARE(calc.sum(-1, 1), 0);
   }
   
   void testMultiply()
   {
       Calculator calc;
       QCOMPARE(calc.multiply(3, 4), 12);
       QCOMPARE(calc.multiply(-2, -3), 6); // Forçant error canviant a 5
   }
};

QTEST_APPLESS_MAIN(TestCalculator) // Sense interfície gràfica. Amb GUI està QTEST_MAIN
#include "testcalculator.moc"

Test unitari

- testqstring.h:

#ifndef TESTQSTRING_H
#define TESTQSTRING_H

#include <QTest>

class TestQString: public QObject
{
   Q_OBJECT
private slots:
   void toUpper();
};

#endif // TESTQSTRING_H

- testqstring.cpp:

#include "testqstring.h"

void TestQString::toUpper()
{
   QString str = "Hello";
   // QVERIFY(str.toUpper() == "HELLO");
   QCOMPARE(str.toUpper(), QString("HELLO"));
}

QTEST_MAIN(TestQString)

Exemple de testing amb QtTest a QML

Codi del projecte test02

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtTest 1.15
...
   TestCase {
       id: testCase
       name: "MathFunctionsTest"
       when: false // Desactivem l'execució automàtica

       // Propietat per emmagatzemar resultats
       property string resultsString: ""

       function runAllTests() {
           resultsString = "";
           var tests = ["test_addNumbers", "test_multiplyNumbers"];

           for (var i = 0; i < tests.length; i++) {
               var testName = tests[i];
               try {
                   this[testName]();
                   resultsString += "✓ PASS: " + testName + "\n";
                   console.log("PASS:", testName);
               } catch (e) {
                   resultsString += "✗ FAIL: " + testName + " - " + e + "\n";
                   console.error("FAIL:", testName, "-", e);
               }
           }

           statusLabel.text = "Tests completats!\n" + resultsString;
       }

       function test_addNumbers() {
           compare(addNumbers(2, 3), 5);
           compare(addNumbers(-1, -1), -2);
       }

       function test_multiplyNumbers() {
           compare(multiply(3, 4), 12);
           compare(multiply(-2, -3), 5); // Error deliberat
       }

       function addNumbers(a, b) {
           return a + b;
       }

       function multiply(a, b) {
           return a * b;
       }
   }

Documentació sobre testing