Skip to content

Latest commit

 

History

History
420 lines (315 loc) · 9.13 KB

File metadata and controls

420 lines (315 loc) · 9.13 KB

Testy Jednostkowe - QR Generator

Przegląd

Projekt zawiera testy jednostkowe napisane z użyciem Qt Test Framework. Testy pokrywają kluczowe funkcjonalności:

  • Walidację danych wejściowych (URL, email, telefon)
  • Szyfrowanie i deszyfrowanie haseł WiFi

Wymagania

  • Qt6 z modułem Test
  • CMake 3.16+
  • Kompilator C++17

Instalacja Qt Test:

# Ubuntu/Debian
sudo apt install qt6-base-dev libqt6test6

# Arch Linux
sudo pacman -S qt6-base

# Fedora
sudo dnf install qt6-qtbase-devel

Kompilacja z Testami

Domyślnie (z testami):

mkdir build && cd build
cmake ..
make

Wyłączenie testów:

cmake -DBUILD_TESTS=OFF ..
make

Uruchamianie Testów

Wszystkie testy (CTest):

cd build
ctest --output-on-failure

Przykładowe wyjście:

Test project /home/user/QR_Generator/build
    Start 1: ValidationTests
1/2 Test #1: ValidationTests ..................   Passed    0.12 sec
    Start 2: EncryptionTests
2/2 Test #2: EncryptionTests ..................   Passed    0.34 sec

100% tests passed, 0 tests failed out of 2

Poszczególne testy:

Test walidacji:

./test_validation

Przykładowe wyjście:

********* Start testing of TestValidation *********
Config: Using QtTest library 6.x.x
PASS   : TestValidation::initTestCase()
PASS   : TestValidation::testValidUrl(simple https)
PASS   : TestValidation::testValidUrl(with path)
PASS   : TestValidation::testInvalidUrl(empty)
PASS   : TestValidation::testValidEmail(simple)
PASS   : TestValidation::testInvalidEmail(no @)
PASS   : TestValidation::cleanupTestCase()
Totals: 25 passed, 0 failed, 0 skipped, 0 blacklisted, 234ms
********* Finished testing of TestValidation *********

Test szyfrowania:

./test_encryption

Przykładowe wyjście:

********* Start testing of TestEncryption *********
Config: Using QtTest library 6.x.x
PASS   : TestEncryption::initTestCase()
PASS   : TestEncryption::testEncryptDecrypt(simple)
PASS   : TestEncryption::testEmptyPassword()
PASS   : TestEncryption::testUnicodePassword()
PASS   : TestEncryption::testLongPassword()
PASS   : TestEncryption::testSaltUniqueness()
PASS   : TestEncryption::cleanupTestCase()
Totals: 12 passed, 0 failed, 0 skipped, 0 blacklisted, 456ms
********* Finished testing of TestEncryption *********

Szczegółowe Testy

Testy Walidacji (test_validation.cpp)

URL Validation

Testowane przypadki:

Przykładowy test:

void TestValidation::testValidUrl() {
    QFETCH(QString, url);
    QVERIFY2(m_generator->isValidUrl(url),
             qPrintable(QString("URL should be valid: %1").arg(url)));
}

Email Validation

Testowane przypadki:

Phone Validation

Testowane przypadki:

  • ✅ Formaty międzynarodowe: +48 123 456 789, (48) 123-456-789
  • ✅ Pusty numer (opcjonalny)
  • ❌ Niepoprawne: litery, za krótkie, znaki specjalne

Testy Szyfrowania (test_encryption.cpp)

Encrypt/Decrypt Cycle

Testowane przypadki:

  • Proste hasła: "password123"
  • Znaki specjalne: "p@ssw0rd!#$%"
  • Spacje: "my password 123"
  • Unicode: "Zażółć gęślą jaźń 日本語"
  • Długie hasła (>64 znaki)

Test:

void TestEncryption::testEncryptDecrypt() {
    QFETCH(QString, password);

    QString encrypted;
    QMetaObject::invokeMethod(m_generator, "encryptPassword",
                             Qt::DirectConnection,
                             Q_RETURN_ARG(QString, encrypted),
                             Q_ARG(QString, password));

    QString decrypted;
    QMetaObject::invokeMethod(m_generator, "decryptPassword",
                             Qt::DirectConnection,
                             Q_RETURN_ARG(QString, decrypted),
                             Q_ARG(QString, encrypted));

    QCOMPARE(decrypted, password);
}

Salt Uniqueness

Test: Dwukrotne zaszyfrowanie tego samego hasła powinno dać różne wyniki (losowy salt)

void TestEncryption::testSaltUniqueness() {
    QString password = "test123";

    QString encrypted1 = encryptPassword(password);
    QString encrypted2 = encryptPassword(password);

    // Różne zaszyfrowane wartości
    QVERIFY2(encrypted1 != encrypted2, "Salt should be random");

    // Ale oba deszyfrują się do tego samego
    QCOMPARE(decryptPassword(encrypted1), password);
    QCOMPARE(decryptPassword(encrypted2), password);
}

Tryb Verbose

Dla bardziej szczegółowego wyjścia:

# Wszystkie testy z pełnymi logami
ctest --verbose

# Pojedynczy test z debugiem
./test_validation -v2

# Z funkcjami debugowania Qt
QT_LOGGING_RULES="*.debug=true" ./test_validation

Coverage (Pokrycie Kodu)

Aby zmierzyć pokrycie testami:

1. Kompilacja z coverage:

mkdir build-coverage && cd build-coverage
cmake -DCMAKE_CXX_FLAGS="--coverage" -DCMAKE_BUILD_TYPE=Debug ..
make

2. Uruchomienie testów:

ctest

3. Generowanie raportu (lcov):

# Instalacja lcov
sudo apt install lcov  # Ubuntu/Debian
sudo pacman -S lcov    # Arch Linux

# Generowanie raportu
lcov --capture --directory . --output-file coverage.info
lcov --remove coverage.info '/usr/*' '*/tests/*' --output-file coverage_filtered.info
genhtml coverage_filtered.info --output-directory coverage_html

# Otwórz w przeglądarce
xdg-open coverage_html/index.html

Oczekiwane pokrycie:

  • Walidacja: ~95%
  • Szyfrowanie: ~90%
  • Całość: ~70% (wiele kodu UI jest trudne do przetestowania)

Continuous Integration (CI)

GitHub Actions (przykład):

Utwórz .github/workflows/tests.yml:

name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Install dependencies
      run: |
        sudo apt update
        sudo apt install -y qt6-base-dev libqrencode-dev libopencv-dev

    - name: Build
      run: |
        mkdir build && cd build
        cmake ..
        make

    - name: Run tests
      run: |
        cd build
        ctest --output-on-failure

Dodawanie Nowych Testów

Struktura testu:

#include <QtTest/QtTest>
#include "qrgenerator.h"

class TestNewFeature : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();      // Przed wszystkimi testami
    void init();              // Przed każdym testem
    void testSomething();     // Twój test
    void cleanup();           // Po każdym teście
    void cleanupTestCase();   // Po wszystkich testach

private:
    QRGenerator* m_generator;
};

void TestNewFeature::initTestCase() {
    m_generator = new QRGenerator();
}

void TestNewFeature::testSomething() {
    // Arrange
    QString input = "test data";

    // Act
    QString result = m_generator->someMethod(input);

    // Assert
    QCOMPARE(result, "expected");
    QVERIFY(!result.isEmpty());
}

QTEST_MAIN(TestNewFeature)
#include "test_new_feature.moc"

Dodanie do CMakeLists.txt:

# W sekcji BUILD_TESTS
add_executable(test_new_feature tests/test_new_feature.cpp)
target_link_libraries(test_new_feature PRIVATE qrgenerator_lib Qt6::Test)
add_test(NAME NewFeatureTests COMMAND test_new_feature)

Debugowanie Testów

Użycie GDB:

gdb ./test_validation
(gdb) run
(gdb) bt  # backtrace gdy test failuje

Użycie Valgrind (wycieki pamięci):

valgrind --leak-check=full ./test_validation

Qt Creator:

  1. Otwórz projekt w Qt Creator
  2. Przejdź do "Projects" → "Build & Run" → "Test"
  3. Kliknij prawym na test → "Debug test"

Najczęstsze Problemy

Test nie kompiluje się:

error: no member named 'isValidUrl' in 'QRGenerator'

Rozwiązanie: Upewnij się, że metoda jest publiczna lub dodaj friend class TestValidation; do klasy.

Test failuje mimo poprawnego kodu:

FAIL!  : TestValidation::testValidUrl(simple https) Compared values are not the same

Rozwiązanie: Sprawdź dane testowe (_data() funkcja) i warunki QCOMPARE.

Testy przechodzą lokalnie ale failują na CI:

  • Sprawdź różnice w wersjach Qt
  • Upewnij się, że wszystkie zależności są zainstalowane
  • Sprawdź różnice w locale (np. formaty dat)

Benchmarking

Dla testów wydajności dodaj:

void TestEncryption::benchmarkEncryption() {
    QString password = "test_password_123";

    QBENCHMARK {
        QString encrypted = encryptPassword(password);
    }
}

Uruchom:

./test_encryption -tickcounter

Dokumentacja Qt Test


Uwaga: Testy są automatycznie uruchamiane jeśli BUILD_TESTS=ON (domyślnie). Dla release builds możesz wyłączyć testy używając -DBUILD_TESTS=OFF.


Dokument utworzony: 2025-11-18 Ostatnia aktualizacja: 2025-11-18