Alle Unit-Tests in einer ausführbaren Datei oder aufteilen?

12

Möchten Sie beim Schreiben von Tests für eine Software, z. B. eine Bibliothek, alle Komponententests zu einem einzigen kompilieren oder in mehrere ausführbare Dateien aufteilen?

Der Grund, den ich frage , ist, dass ich derzeit CUnit verwende , um eine Bibliothek zu testen, an der ich arbeite. Die Tests sind in separate Suites unterteilt, die zu einer ausführbaren Datei mit gedruckter Ausgabe für Fehler kompiliert werden. Das Build-System für diese Bibliothek ist CMake (das trotz seines Namens wenig mit CUnit zu tun hat), das mit seinem eigenen Testframework , CTest , geliefert wird . Mit CTest kann ich eine Liste der ausführbaren Dateien registrieren, die als Tests dienen.

Ich überlege, ob ich CTest für automatisierte Testläufe verwenden soll. Dazu müsste ich jedoch die Tests, die ich bisher geschrieben habe, in separate Kompilierungsziele aufteilen. Ansonsten kann ich einige der erweiterten Funktionen von CTests nicht wirklich nutzen, z. B. das selektive Ausführen von Tests.

Mir ist klar, dass dies eher eine Frage der zu verwendenden Tools und ihrer Handhabung und Konventionen ist, aber gibt es ansonsten noch andere Gründe, einen einzelnen ausführbaren Test einem separaten vorzuziehen? Oder umgekehrt?

Benjamin Kloster
quelle
Teilen Sie sie nach Klassen in separate ausführbare Dateien auf. Jede Klasse sollte einen eigenen Unit-Test haben, es sei denn, die Klasse ist nicht Unit-testbar und muss daher indirekt von anderen Klassen getestet werden.
Brian
1
Wenn Sie eine große Bibliothek mit Hunderten von Klassen mit jeweils einem Komponententest haben, ist die Erstellungszeit viel länger, wenn Sie für jede eine vollständige Binärdatei erstellen, als für eine (oder mehrere) große Binärdateien. Außerdem müssen viele Makefiles verwaltet werden, von denen jedes einzelne Verknüpfungslinien enthält.
JBRWilkinson
Es ist nicht so groß. Weniger als 20 Module. Ich kann sie auch alle mit den gleichen Flags kompilieren, sodass CMake die Makefiles ohne viel Arbeit von meiner Seite erstellen kann.
Benjamin Kloster

Antworten:

5

Ich lasse meine automatisierten Tests gerne in einzelnen Binärdateien oder zumindest nach "zusammengehörigen" Gruppen gruppieren und rufe sie dann über ein einfaches Shell-Skript auf (wobei ein Exit-Code ungleich Null einen Fehler anzeigt und die Ausgabe auf stderr erfasst werden kann eine Erklärung aufzeichnen). Auf diese Weise habe ich die volle Flexibilität beim Testen - ich kann einzelne Tests direkt über die Befehlszeile ausführen, ich kann alle möglichen ausgefallenen Skripte erstellen, ich kann sie nach Belieben neu anordnen, ohne etwas neu zu kompilieren usw.

Noch wichtiger ist jedoch, dass ich Tests, die in verschiedenen Sprachen geschrieben wurden oder verschiedene Toolchains verwenden, in ein und derselben Ausführung einfügen kann. Zum Beispiel sind die Unit-Tests, die ich schreibe, höchstwahrscheinlich in der Hauptsprache des Projekts, und ihre Ausführung ist eine Frage des Erstellens und Aufrufens der Binärdateien. Ich möchte aber auch meine Datenbank testen und möglicherweise SQL-Skripte direkt in die Datenbank einspeisen. Ich möchte vielleicht ein statisches Code-Analyse-Tool für meinen Code ausführen (auch wenn es sich nur um eine Art Linter handelt). Möglicherweise möchte ich meinen statischen HTML-Code über eine Gültigkeitsprüfung ausführen. Ich könnte einen grepBefehl über die Codebasis ausführen , um nach verdächtigen Konstrukten, Verstößen gegen den Codestil oder Stichwörtern mit der roten Flagge zu suchen. Die Möglichkeiten sind endlos - wenn es von der Kommandozeile ausgeführt werden kann und sich an "Null Exit Status bedeutet OK" hält, kann ich es verwenden.

tdammers
quelle
Das sprachunabhängige Argument ist ein sehr guter Punkt, da ich beabsichtige, Python-Bindungen für die Bibliothek später zu implementieren. Vielen Dank!
Benjamin Kloster
@tdammers: Gibt es ein bestimmtes Test-Framework?
JBRWilkinson
@ JBRWilkinson: Nur ein 30-zeiliges Shell-Skript. Für die meisten Sprachen, die ich verwende, gibt es kleine Bibliotheken, die häufig zum Testen verwendet werden, beispielsweise zum Ausführen einer Funktion, zum Vergleichen des Ergebnisses mit einem erwarteten Wert und zum Auslösen, wenn sie nicht übereinstimmen. Aber jedes gegebene Unit-Test-Framework könnte leicht in ein solches "Meta-System" integriert werden, solange es von der Kommandozeile ausgeführt werden kann und Erfolg / Misserfolg durch seinen Exit-Status signalisiert.
tdammers
2

Ich habe in der Regel eine Bibliothek für die Komponententests einer Anwendung (oder für ein Paket von Bibliotheken, die gemeinsam genutzt werden). In dieser Bibliothek versuche ich, die Namespaces der zu testenden Objekte für die Test-Fixtures zu replizieren oder zu approximieren (meistens verwende ich NUnit). Dies vereinfacht die Kompilierung, da in .NET das Erstellen jeder Binärdatei mit einem Mehraufwand verbunden ist, der die Erstellungszeit einer Lösung mit 20 Projekten gegenüber einer Lösung mit 10 Projekten mit demselben LOC verlängert. Test-Binärdateien werden sowieso nicht verteilt, daher dient jede Gliederung der Tests in Binärdateien Ihrer eigenen Bequemlichkeit, und ich finde, dass YAGNI hier wie überall anwendbar ist.

Jetzt habe ich normalerweise nicht die Überlegungen, die tdammers hat; Mein Code ist praktisch nur in einer Sprache und jeder Test mit SQL-Zeichenfolgen ist kein Komponententest (es sei denn, Sie testen, dass ein Abfrageproduzent die erwartete SQL-Zeichenfolge anhand bestimmter Kriterien zurückgibt), und ich teste praktisch nie die tatsächlichen Komponenten Benutzeroberfläche (in vielen Situationen ist es einfach unmöglich). Ich verwende auch eine Unit-Testing-Bibliothek, die von Tools von Drittanbietern wie Build-Bots und IDE-Plugins gut angenommen wird. Daher sind Bedenken hinsichtlich der Ausführung einzelner Tests, Teil-Suites usw. minimal.

KeithS
quelle
1
Eine Frage der Kultur, denke ich - in einer .NET-Umgebung würde ich wahrscheinlich genauso argumentieren wie Sie.
Tdammers