8 Stimmen

Wie organisiert man C++-Testanwendungen und zugehörige Dateien?

Ich arbeite an einer C++-Bibliothek, die (neben anderen Dingen) Funktionen zum Lesen von Konfigurationsdateien hat; und ich möchte Tests dafür hinzufügen. Bis jetzt hat das dazu geführt, dass ich viele gültige und ungültige Konfigurationsdateien erstellt habe, jede mit nur ein paar Zeilen, die eine bestimmte Funktionalität testen. Aber es ist jetzt sehr unhandlich geworden, da es so viele Dateien gibt, und auch viele kleine C++-Testanwendungen. Irgendwie kommt mir das falsch vor :-) haben Sie also Tipps, wie man all diese Tests, die Testanwendungen und die Testdaten organisieren kann?

Hinweis: Die öffentliche API der Bibliothek selbst ist nicht leicht zu testen (sie erfordert eine Konfigurationsdatei als Parameter). Die pikanten, fehleranfälligen Methoden zum Lesen und Interpretieren von Konfigurationswerten sind privat, so dass ich keine Möglichkeit sehe, sie direkt zu testen?

Also: Würden Sie beim Testen gegen echte Dateien bleiben; und wenn ja, wie würden Sie all diese Dateien und Anwendungen so organisieren, dass sie noch wartbar sind?

6voto

richq Punkte 53842

Vielleicht könnte die Bibliothek eine Art Stream-Eingabe akzeptieren, so dass Sie ein stringähnliches Objekt übergeben und alle Eingabedateien vermeiden könnten? Oder, je nach Art der Konfiguration, könnten Sie "get/setAttribute()"-Funktionen bereitstellen, um die Parameter direkt und öffentlich zu verändern. Wenn das nicht wirklich ein Designziel ist, dann ist das auch egal. Datengesteuerte Unit-Tests sind an einigen Stellen verpönt, aber es ist definitiv besser als nichts! Ich würde den Code wahrscheinlich wie folgt gestalten:

  project/
          src/
          tests/
                test1/
                      input/
                test2
                      input/

In jedem testN-Verzeichnis würden Sie eine cpp-Datei haben, die mit den Konfigurationsdateien im Eingabeverzeichnis verknüpft ist.

Wenn Sie eine Testbibliothek im Stil von xUnit verwenden ( cppunit , googletest , unittest++ oder was auch immer) können Sie verschiedene testXXX()-Funktionen zu einer einzigen Klasse hinzufügen, um damit verbundene Funktionsgruppen zu testen. Auf diese Weise könnten Sie einen Teil des Problems der vielen kleinen Programme vermeiden, indem Sie zumindest einige Tests zusammenfassen.

Das einzige Problem dabei ist, dass die Bibliothek erwartet, dass die Konfigurationsdatei einen bestimmten Namen trägt oder sich an einem bestimmten Ort befindet. Das sollte nicht der Fall sein, aber falls doch, muss man es umgehen, indem man die Testdatei an den erwarteten Ort kopiert.

Und machen Sie sich keine Sorgen, dass viele Tests Ihr Projekt durcheinander bringen, wenn sie in einem Testverzeichnis versteckt sind, werden sie niemanden stören.

1voto

Rob Wells Punkte 35303

Teil 1.

Wie Richard vorschlug, würde ich einen Blick auf die CPPUnit Test-Framework. Dies bestimmt bis zu einem gewissen Grad den Standort Ihres Test-Frameworks.

Ihre Tests können sich in einem parallelen Verzeichnis auf höchster Ebene befinden, wie in Richards Beispiel, oder in Testunterverzeichnissen oder Testverzeichnissen parallel zu dem Bereich, den Sie testen wollen.

Wie auch immer, achten Sie bitte auf eine einheitliche Verzeichnisstruktur für das gesamte Projekt! Insbesondere für den Fall, dass die Tests in einem einzigen übergeordneten Verzeichnis enthalten sind.

Es gibt nichts Schlimmeres, als eine gedankliche Zuordnung des Quellcodes an einem Ort wie diesem vornehmen zu müssen:

/project/src/component_a/piece_2/this_bit

und den/die Test(s) an einem Ort wie z. B.:

/project/test/the_first_components/connection_tests/test_a

Und ich habe an Projekten gearbeitet, bei denen jemand das getan hat!

Was für eine Verschwendung von Wetware-Zyklen! 8-O Das ist ein Verstoß gegen das Alexander-Konzept der "Qualität ohne Namen".

Viel besser ist es, wenn Ihre Tests konsistent mit dem Ort des zu testenden Quellcodes sind:

/project/test/component_a/piece_2/this_bit/test_a

Teil 2

Was die API-Konfigurationsdateien anbelangt, so sollten Sie lokale Kopien einer Referenzkonfiguration in jedem lokalen Testbereich als Teil des Testumgebungs-Setups erstellen, das vor der Ausführung eines Tests ausgeführt wird. Verteilen Sie keine Kopien von Konfigurationsdateien (oder Daten) in Ihrem gesamten Testbaum.

HTH.

Prost,

Rob

Übrigens bin ich wirklich froh, dass Sie diese Frage jetzt stellen, wenn Sie etwas einrichten!

0voto

Anthony Cramp Punkte 4417

Bei einigen Tests habe ich den Testcode verwendet, um die Konfigurationsdateien zu schreiben und sie dann zu löschen, nachdem der Test die Datei verwendet hatte. Das polstert den Code etwas auf und ich habe keine Ahnung, ob das eine gute Praxis ist, aber es hat funktioniert. Wenn Sie boost verwenden, dann ist das Dateisystemmodul nützlich, um Verzeichnisse zu erstellen, in Verzeichnissen zu navigieren und Dateien zu löschen.

0voto

Lev Punkte 6127

Ich stimme dem zu, was @Richard Quirk gesagt hat, aber vielleicht möchten Sie auch Ihre Testsuite-Klasse zu einem Freund der Klasse machen, die Sie testen, und ihre privaten Funktionen testen.

0voto

graham.reeds Punkte 15745

Für solche Dinge habe ich immer eine kleine Utility-Klasse, die eine Konfiguration in einen Speicherpuffer lädt und von dort aus in die eigentliche Config-Klasse eingespeist wird. Das bedeutet, dass die eigentliche Quelle keine Rolle spielt - es könnte eine Datei oder eine Datenbank sein. Für den Unit-Test wird sie fest in einem std::string kodiert, der dann an die Klasse zum Testen übergeben wird. Sie können currup!pte3d-Daten leicht simulieren, um Fehlerpfade zu testen.

Ich benutze UnitTest++ . Ich habe die Tests als Teil des src-Baums. Also:

solution/project1/src <-- source code
solution/project1/src/tests <-- unit test code 
solution/project2/src <-- source code
solution/project2/src/tests <-- unit test code

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X