it-swarm.dev

Wie sollte C ++ Unit Test Code für maximale Unit Test Effizienz organisiert werden?

  • Diese Frage bezieht sich nicht auf Unit Testing Frameworks.
  • Diese Frage bezieht sich auf nicht über das Schreiben von Unit-Tests.
  • Bei dieser Frage geht es um wo, um den geschriebenen Code UT) zu setzen und wie/wann/wo er kompiliert und ausgeführt werden soll.

In Effektiv mit Legacy-Code arbeiten behauptet Michael Feathers dies

gute Unit-Tests ... schnell laufen

und das

Ein Unit-Test, dessen Ausführung 1/10 Sekunde dauert, ist ein langsamer Unit-Test.

Ich denke, diese Definitionen sind sinnvoll. Ich denke auch, dass sie implizieren, dass Sie eine Reihe von Unit-Tests und eine Reihe von Diese Code-Tests, die länger dauern separat aufbewahren müssen, aber ich denke, das ist Der Preis, den Sie zahlen, wenn Sie etwas nur als Unit Test bezeichnen, wenn es (sehr) schnell läuft.

Offensichtlich ist das Problem in C++, dass Sie zum "Ausführen" Ihres Unit-Tests ( s ) Folgendes tun müssen:

  1. Bearbeiten Sie Ihren Code (Produktion oder Unit Test, je nachdem in welchem ​​"Zyklus" Sie sich befinden)
  2. Kompilieren
  3. Verknüpfung
  4. Unit Unit Test Executable starten ( s )

Bearbeiten (nach seltsamer enger Abstimmung): Bevor ich auf die Details eingehe, werde ich versuchen, den Punkt hier zusammenzufassen:

Wie kann C++ Unit Test Code effektiv organisiert werden, so dass es sowohl effizient ist, den (Test-) Code zu bearbeiten als auch den Testcode auszuführen?


Das erste Problem besteht dann darin, wo zu entscheiden, den Unit-Test-Code so zu setzen, dass:

  • es ist "natürlich", es in Kombination mit dem zugehörigen Produktionscode zu bearbeiten und anzuzeigen.
  • es ist einfach/schnell, den Kompilierungszyklus für die Einheit Ihre aktuelle Änderung zu starten

Das zweite verwandte Problem ist dann was zu kompilieren, so dass die Rückmeldung sofort erfolgt.

Extreme Optionen:

  • Jede Unit-Test-Test-Unit befindet sich in einer separaten CPP-Datei und diese CPP-Datei wird separat kompiliert + (zusammen mit der getesteten Quellcode-Unit-Datei) mit einer einzelnen ausführbaren Datei verknüpft, die dann diesen einen Unit-Test ausführt.
    • (+) Dies minimiert die Startzeit (Kompilieren + Verknüpfen!) Für die einzelne Testeinheit.
    • (+) Der Test läuft super schnell, da nur eine Einheit getestet wird.
    • (-) Die Ausführung der gesamten Suite muss eine Unmenge von Prozessen starten. Kann ein Problem zu verwalten sein.
    • (-) Der Overhead der Prozessstarts wird sichtbar
  • Die andere Seite wäre - immer noch - eine CPP-Datei pro Test zu haben, aber alle Test-CPP-Dateien (zusammen mit dem Code, den sie testen!) Sind zu einer ausführbaren Datei verknüpft (pro Modul/pro Projekt/Auswahl Ihrer Wahl).
    • (+) Die Kompilierungszeit wäre weiterhin in Ordnung, da nur geänderter Code kompiliert wird.
    • (+) Die Ausführung der gesamten Suite ist einfach, da nur eine Exe ausgeführt werden muss.
    • (-) Die Verknüpfung der Suite wird ewig dauern, da bei jeder Neukompilierung eines Objekts eine erneute Verknüpfung ausgelöst wird.
    • (-) (?) Der Anzug braucht länger, obwohl Wenn alle Unit-Tests schnell sind, sollte die Zeit in Ordnung sein.

Wie werden C++ Unit Tests in der realen Welt behandelt? Wenn ich das Zeug nur nächtlich/stündlich laufen lasse, spielt der zweite Teil keine Rolle, aber der erste Teil, nämlich wie man den UT Code) mit dem Produktionscode "koppelt", so dass es ist "Natürlich" für Entwickler ist es immer wichtig, beide im Fokus zu behalten. (Und wenn Entwickler den Code UT im Fokus haben), möchten sie ihn ausführen, was uns zum zweiten Teil zurückbringt .)

Geschichten und Erfahrungen aus der realen Welt geschätzt !

Anmerkungen:

  • Diese Frage lässt absichtlich eine nicht spezifizierte Plattform und ein Make/Project-System.
  • Fragen mit Tags UT & C++ ist ein guter Anfang, aber leider konzentrieren sich zu viele Fragen und insbesondere Antworten zu stark auf die Details oder auf bestimmte Frameworks.
  • Vor einiger Zeit beantwortete ich eine ähnliche Frage zur Struktur für Boost-Unit-Tests. Ich finde, dass diese Struktur für "echte", schnelle Unit-Tests fehlt. Und ich finde die andere Frage zu eng, daher diese neue Frage.
48
Martin Ba

Wir haben alle Unit-Tests (für ein Modul) in einer ausführbaren Datei. Die Tests werden in Gruppen eingeteilt. Ich kann einen einzelnen Test (oder einige Tests) oder eine Gruppe von Tests ausführen, indem ich in der Befehlszeile des Testläufers einen (Test-/Gruppen-) Namen angebe. Das Build-System kann die Gruppe "Build" ausführen, die Testabteilung kann "All" ausführen. Der Entwickler kann einige Tests in eine Gruppe wie "BUG1234" einordnen, wobei 1234 die Issue-Tracker-Nummer des Falls ist, an dem er arbeitet.

6
ur.

Erstens bin ich nicht einverstanden mit "1) Bearbeiten Sie Ihren (Produktions-) Code und Ihren Unit-Test". Sie sollten jeweils nur eine Änderung vornehmen. Andernfalls wissen Sie nicht, welche Ursache das Ergebnis verursacht hat, wenn sich das Ergebnis ändert.

Ich mag es, Unit-Tests in einen Verzeichnisbaum zu stellen, der den Hauptbaum beschattet. Wenn ich habe /sources/componentA/alpha/foo.cc und /objects/componentA/beta/foo.o, dann will ich so etwas wie /UTest_sources/componentA/alpha/test_foo.cc und /UTest_objects/componentA/beta/test_foo.o. Ich verwende denselben Schattenbaum für Stub/Mock-Objekte und alle anderen Quellen, die die Tests benötigen. Es wird einige Edge-Fälle geben, aber dieses Schema vereinfacht die Dinge erheblich. Ein gutes Editor-Makro kann die Testquelle mühelos neben der Betreffquelle aufrufen. Ein gutes Build-System (z. B. GNUMake) kann beide kompilieren und den Test mit einem Befehl ausführen (z. B. make test_foo) und kann eine Unmenge solcher Prozesse verwalten - nur diejenigen, deren Quellen sich seit dem letzten Test geändert haben - ganz einfach (ich habe nie festgestellt, dass der Aufwand für das Starten dieser Prozesse ein Problem darstellt, es ist O (N) ).

Im selben Framework können Sie Tests in größerem Maßstab (keine Komponententests mehr) durchführen, die viele Objekte miteinander verknüpfen und viele Tests ausführen. Der Trick besteht darin, diese Tests nach der Zeit zu sortieren, die sie zum Erstellen/Ausführen benötigen, und sie entsprechend in Ihren Tagesplan einzuarbeiten. Führen Sie den Test mit einer Sekunde oder weniger durch, wann immer Sie möchten. Starten Sie den Zehn-Sekunden-Test und dehnen Sie ihn. Fünf-Minuten-Test und Pause; halbstündiger Test und Mittagessen; Sechs-Stunden-Test und nach Hause gehen. Wenn Sie feststellen, dass Sie viel Zeit verschwenden, z. Wenn Sie einen großen Test erneut verknüpfen, nachdem Sie nur eine kleine Datei geändert haben, machen Sie es falsch. Selbst wenn die Verknüpfung sofort erfolgt, würden Sie immer noch einen langen Test ausführen, wenn dies nicht erforderlich wäre.

6
Beta