Archiwa tagu: testy jednostkowe

Qt Unit Test – projekt z kilkoma klasami testowymi

Mając chwilowe problemy z dotychczasowym frameworkiem do testów jednostkowych postanowiłem przyjrzeć się frameworkowi wbudowanemu w Qt: Qt Test.

Pierwszy problem pojawia się gdy po stworzeniu nowego projektu Qt Unit Test w Qt Creatorze próbujemy go odpalić w konfiguracji debug. Kończy się to błędem „moc: Too many input files specified: „. Problem wynika ze spacji w ścieżce. Można go rozwiązać usuwając jedną linię z pliku *.pro:

Druga sprawa dotyczy architektury frameworka Qt Unit Test. Domyślny projekt testowy stworzony w Qt Creatorze zawiera tylko jedną klasę testową. W plikach źródłowych Qt każda klasa testowa jest osobnym projektem, a te projekty połączone są w strukturę drzewa za pomocą projektów subdirs. Domyślnie funkcja main w projektach testowych jest implementowana poprzez makro

i pozwala na dodanie tylko jednej klasy z testami jednostkowymi. Aby móc stworzyć projekt zawierający kilka klas z testami i jedną funkcją main wystarczy tę funkcję main ręcznie zaimplementować:

Link do kompletnego projektu: Qt-simple-examples/QTestMultipleTestClasses

Innym sprawą, która skłoniła mnie do przejścia z Catcha na Qt Unit Test był problem związany z obsługą biblioteki Catch przez Qt Creatora. Podczas zmiany nazwy metody lub klasy za pomocą polecenia Refactor -> Reaname Symbol Under Cursor, Qt Creator widzi jedynie użycia zmienianej metody lub klasy w projekcie aplikacji, natomiast nie widzi wystąpień tych nazw w projekcie test (który używa Catcha). Gdy w projekcie test użyta zostanie biblioteka Qt Test to Qt Creator nie będzie miał już problemów i zmieni nazwy wszystkich wystąpień edytowanej nazwy.

Qt test – unresolved external symbol metaObject – rozwiązanie

Dotychczasowy framework do testów jednostkowych Catch nie chciał zbytnio współpracować z klasami dziedziczącymi po QObject. Przy próbie kompilacji zwracał błąd: „LNK2001: unresolved external symbol „public: virtual struct QMetaObject const * __cdecl BlocksDescriptionField::metaObject(void)const”. Rozwiązaniem okazało się dodanie plików nagłówkowych w pliku *.pro:

Catch – problemy przy testowaniu plików *.cpp – unresolved external symbol

Pojawiły się pewne problemy przy testowaniu plików *.cpp. Dotychczas wszystkie pliki aplikacji objęte testami były zdefiniowane w plikach nagłówkowych *.h, więc problem się nie ujawniał, bo nie był potrzebny żaden kod z plików *.cpp. Dzisiaj postanowiłem napisać test do dość rozbudowanej klasy, której konstruktor został zdefiniowany w pliku *.cpp i niestety pojawił się błąd „unresolved external symbol”. Trochę czasu zajęło mi znalezienie przyczyny, którą był brak dołączonych plików *.cpp zawierających definicje konstruktorów i metod. Rozwiązaniem problemu było dołączenie plików *.cpp aplikacji do projektu test.pro.

Czytaj dalej

Testy jednostkowe w Qt Creatorze

W tym poście zostanie przedstawiona struktura projektu zawierającego aplikację oraz testy jednostkowe. Przedstawię dwa przykłady. Pierwszy z nich będzie oparty o wbudowaną bibliotekę QtTest, natomiast w drugim przykładzie zostanie wykorzystana biblioteka Catch, która jest lekka i składa się tylko z jednego pliku nagłówkowego.

Struktura projektu

TemplateProj struktura.png

Projekt (TemplateProj) składa się z dwóch podprojektów: standardowego projektu aplikacji (app) oraz projektu zawierającego testy jednostkowe (tests). Główny projekt (TemplateProj) to tak naprawdę tylko kontener na pozostałe projekty. Korzysta z szablonu TEMPLATE = subdirs i definiuje jedynie nazwy podkatalogów projektu. CONFIG += ordered informuje kompilator, że wymienione podkatalogi powinny być przetwarzane w takiej kolejności w jakiej są wymienione. Zapewnia to poprawną kompilację, ponieważ projekt tests korzysta z elementów projektu app. Zawartość pliku TemplateProj:

Projekt app jest generalnie standardowym projektem aplikacji, takim jaki można stworzyć w Qt Creatorze z szablonu nowy projekt. Wpis CONFIG += console umożliwia prawidłowe działanie programu, gdy odpalamy program w terminalu zamiast domyślnego okna application output. Brak tego wpisu powoduje, że po odpaleniu aplikacji okno konsoli jest puste i wyświetla tylko standardowe „Press Return to close this window”. Zmiana opcji „Run in terminal” jest dostępna w karcie Projects → Run Settings osobno dla każdej aplikacji. DESTDIR = $$PWD/../build ustawia katalog z plikami wynikowymi na build w katalogu głównym projektu. Można tę linię pominąć, wtedy pliki wynikowe pojawią się w domyślnych katalogach debug / release.

W głównym projekcie app dodajmy plik main.cpp oraz przykładową klasę Calculator:

Do tego miejsca wszystkie elementy są niezależne od użytej technologii testów. Natomiast projekt z testami jest już dostosowywany do danej biblioteki testowej.

QtTest

QtTest to biblioteka dostarczana wraz z całym pakietem Qt, więc stworzenie projektu zawierającego testy jednostkowe jest możliwe bez wprowadzania dodatkowych zależności od zewnętrznych bibliotek.
Najprostszy plik projektu tests dla QtTest wygląda następująco:

Plik TestMain.cpp (omówienie):

Link do kompletnego projektu: Qt-simple-examples/ProjectStructureQTest

Catch

Catch to biblioteka testów dla C++. Jej zaletami są liberalna licencja, brak zależności od innych bibliotek oraz dystrybucja w postaci jednego pliku nagłówkowego.
Najprostszy plik projektu tests dla Catch wygląda następująco (chociaż działa także bez linijki TEMPLATE = app, ale została ona pozostawiona dla formalności):

Plik TestMain.cpp – odpowiada za prawidłowe wywołanie pozostałych plików źródłowych z testami. Zawiera w sobie definicje jednego makra i include biblioteki Catch. Makro CATCH_CONFIG_MAIN powinno zostać wywołane tylko w jednym miejscu projektu.

Właściwy plik z testami:

Link do kompletnego projektu: Qt-simple-examples/ProjectStructureCatch
O strukturze projektu: link
Przykład aplikacji wykorzystującej bibliotekę Catch: link

Potencjalne problemy

  • qmake exited with code 2 – prawdopodobnie ścieżka projektu jest zbyt długa – wystarczy przenieść projekt do katalogu o krótszej ścieżce
  • inne błędy przy kompilacji – kliknąć prawym przyciskiem na projekcie → Run qmake a następnie Rebuild