Derzeit haben wir in meinem Job eine große Reihe von Komponententests für unsere C ++ - Anwendung. Wir verwenden jedoch kein Unit-Test-Framework. Sie verwenden einfach ein C-Makro, das im Grunde ein Assert und ein Cout umschließt. So etwas wie:
VERIFY(cond) if (!(cond)) {std::cout << "unit test failed at " << __FILE__ << "," << __LINE__; asserst(false)}
Dann erstellen wir einfach Funktionen für jeden unserer Tests wie
void CheckBehaviorYWhenXHappens()
{
// a bunch of code to run the test
//
VERIFY(blah != blah2);
// more VERIFY's as needed
}
Unser CI-Server erkennt "Komponententest fehlgeschlagen" und schlägt beim Erstellen fehl und sendet die Nachricht per E-Mail an die Entwickler.
Und wenn wir doppelten Setup-Code haben, überarbeiten wir ihn einfach wie jeden anderen duplizierten Code, den wir in der Produktion haben würden. Wir packen es hinter Hilfsfunktionen, lassen einige Testklassen einpacken und häufig verwendete Szenarien einrichten.
Ich weiß, dass es Frameworks wie CppUnit und Boost Unit Test gibt. Ich frage mich, welchen Wert diese hinzufügen? Vermisse ich, was diese auf den Tisch bringen? Gibt es etwas Nützliches, das ich von ihnen gewinnen könnte? Ich zögere, eine Abhängigkeit hinzuzufügen, es sei denn, sie schafft einen echten Mehrwert, zumal das, was wir haben, einfach zu sein scheint und gut funktioniert.
quelle
Scheint, als ob Sie bereits ein Framework verwenden, ein hausgemachtes.
Was ist der Mehrwert von populäreren Frameworks? Ich würde sagen, dass der Mehrwert darin besteht, dass Sie Code mit Personen außerhalb Ihres Unternehmens austauschen können, da er auf dem bekannten und weit verbreiteten Framework basiert .
Ein selbst erstelltes Framework hingegen zwingt Sie dazu, entweder Ihren Code niemals freizugeben oder das Framework selbst bereitzustellen, was mit dem Wachstum des Frameworks selbst umständlich werden kann.
Wenn Sie einem Kollegen Ihren Code so wie er ist, ohne Erklärung und ohne Unit-Test-Framework, geben, ist er nicht in der Lage, ihn zu kompilieren.
Ein zweiter Nachteil von hausgemachten Frameworks ist die Kompatibilität . Gängige Unit-Test-Frameworks stellen in der Regel die Kompatibilität mit verschiedenen IDEs, Versionskontrollsystemen usw. sicher. Im Moment ist dies möglicherweise nicht sehr wichtig für Sie, aber was passiert, wenn Sie eines Tages etwas auf Ihrem CI-Server ändern oder migrieren müssen zu einer neuen IDE oder einem neuen VCS? Wirst du das Rad neu erfinden?
Zu guter Letzt bieten größere Frameworks mehr Funktionen, die Sie möglicherweise eines Tages in Ihrem eigenen Framework implementieren müssen.
Assert.AreEqual(expected, actual)
ist nicht immer genug. Was ist, wenn Sie Folgendes benötigen:Präzision messen?
ungültiger Test, wenn er zu lange läuft? Das erneute Implementieren eines Timeouts ist möglicherweise selbst in Sprachen, die eine asynchrone Programmierung ermöglichen, nicht einfach.
Eine Methode testen, bei der eine Ausnahme erwartet wird?
Haben Sie einen eleganteren Code?
ist in Ordnung, aber ist es nicht ausdrucksvoller für Ihre Absicht, stattdessen die nächste Zeile zu schreiben?
quelle
Wie andere bereits gesagt haben, haben Sie bereits Ihr eigenes, hausgemachtes Framework.
Der einzige Grund, warum ich andere Test-Frameworks verwenden kann, ist aus Sicht der Branche "allgemein bekannt". Neue Entwickler müssten nicht lernen, wie man es zu Hause macht (obwohl es sehr einfach aussieht).
Andere Test-Frameworks bieten möglicherweise weitere Funktionen, die Sie nutzen können.
quelle
Sie haben bereits ein Framework, auch wenn es ein einfaches ist.
Die Hauptvorteile eines größeren Frameworks, wie ich sie sehe, sind die Fähigkeit, viele verschiedene Arten von Behauptungen zu haben (wie das Behaupten von Erhöhungen), eine logische Reihenfolge für die Komponententests und die Fähigkeit, nur eine Teilmenge von Komponententests unter auszuführen eine Zeit. Auch das Muster von xUnit-Tests ist recht gut zu befolgen, wenn Sie können - zum Beispiel das von setUP () und tearDown (). Das sperrt Sie natürlich in diesen Rahmen. Beachten Sie, dass einige Frameworks eine bessere Scheinintegration aufweisen als andere - zum Beispiel google mock and test.
Wie lange dauert es, bis Sie alle Unit-Tests auf ein neues Framework umgestellt haben? Tage oder ein paar Wochen sind es vielleicht wert, aber mehr vielleicht nicht so sehr.
quelle
So wie ich das sehe, habt ihr beide den Vorteil und seid im "Nachteil".
Der Vorteil ist, dass Sie ein System haben, mit dem Sie sich wohl fühlen und das für Sie funktioniert. Sie sind froh, dass dies die Gültigkeit Ihres Produkts bestätigt, und Sie würden wahrscheinlich keinen geschäftlichen Nutzen daraus ziehen, zu versuchen, alle Ihre Tests für etwas zu ändern, das ein anderes Framework verwendet. Wenn Sie Ihren Code umgestalten können und Ihre Tests die Änderungen übernehmen - oder noch besser, wenn Sie Ihre Tests ändern können und Ihr vorhandener Code die Tests nicht besteht, bis er umgestaltet wird, sind alle Grundlagen abgedeckt. Jedoch...
Einer der Vorteile einer gut gestalteten Unit-Testing-API besteht darin, dass die meisten modernen IDEs viel native Unterstützung bieten. Dies hat keine Auswirkungen auf das Hardcore-VI und die Emac-Benutzer, die sich über die Visual Studio-Benutzer lustig machen. Für diejenigen, die eine gute IDE verwenden, haben Sie jedoch die Möglichkeit, Ihre Tests zu debuggen und innerhalb dieser auszuführen die IDE selbst. Dies ist gut, jedoch gibt es je nach verwendetem Framework einen noch größeren Vorteil, und zwar in der Sprache, die zum Testen Ihres Codes verwendet wird.
Wenn ich Sprache sage , spreche ich nicht von einer Programmiersprache, sondern von einem umfangreichen Satz von Wörtern, die in einer fließenden Syntax zusammengefasst sind, die Testcode wie eine Geschichte lesen lässt. Insbesondere bin ich ein Verfechter der Verwendung von BDD- Frameworks geworden. Meine persönliche Lieblings-DotNet BDD- API ist StoryQEs gibt jedoch mehrere andere, die denselben grundlegenden Zweck haben: ein Konzept aus einem Anforderungsdokument herauszunehmen und es in Code zu schreiben, ähnlich wie es in der Spezifikation geschrieben ist. Die wirklich guten APIs gehen jedoch noch weiter, indem sie jede einzelne Anweisung innerhalb eines Tests abfangen und angeben, ob diese Anweisung erfolgreich ausgeführt wurde oder fehlgeschlagen ist. Dies ist unglaublich nützlich, da Sie den gesamten Test sehen können, der ausgeführt wird, ohne vorzeitig zurückzukehren. Dies bedeutet, dass Ihre Debug-Bemühungen unglaublich effizient werden, da Sie sich nur auf die Teile des Tests konzentrieren müssen, die fehlgeschlagen sind, ohne den gesamten Aufruf entschlüsseln zu müssen Sequenz. Die andere nette Sache ist, dass die Testausgabe Ihnen alle diese Informationen zeigt,
Als Beispiel für das, wovon ich spreche, vergleiche Folgendes:
Verwenden von Asserts:
Verwenden einer fließenden BDD-API: (Stellen Sie sich vor, die kursiven Bits sind im Grunde Methodenzeiger.)
Nun ist die BDD-Syntax zwar länger und wortreicher, und diese Beispiele sind schrecklich erfunden. Für sehr komplexe Testsituationen, in denen sich aufgrund eines bestimmten Systemverhaltens eine Menge Dinge in einem System ändern, bietet Ihnen die BDD-Syntax jedoch Klarheit Beschreibung, was Sie testen und wie Ihre Testkonfiguration definiert wurde, und Sie können diesen Code einem Nicht-Programmierer zeigen, und er wird sofort verstehen, was los ist. Wenn "variable_A" in beiden Fällen den Test nicht besteht, wird das Asserts-Beispiel erst nach dem ersten Assert ausgeführt, nachdem Sie das Problem behoben haben. Die BDD-API führt nacheinander alle in der Kette aufgerufenen Methoden aus und gibt an, welche einzelne Teile der Aussage waren fehlerhaft.
Persönlich finde ich, dass dieser Ansatz viel besser funktioniert als die herkömmlicheren xUnit-Frameworks in dem Sinne, dass die Testsprache dieselbe Sprache ist, in der Ihre Kunden über ihre logischen Anforderungen sprechen. Trotzdem habe ich es geschafft, xUnit-Frameworks in einem ähnlichen Stil zu verwenden, ohne eine vollständige Test-API erfinden zu müssen, um meine Bemühungen zu unterstützen, und obwohl die Behauptungen sich selbst effektiv kurzschließen, lesen sie sich sauberer. Zum Beispiel:
Mit Nunit :
Wenn Sie sich für die Verwendung einer Unit-Testing-API entscheiden, empfehle ich, einige Zeit mit einer großen Anzahl verschiedener APIs zu experimentieren und Ihren Ansatz offen zu halten. Während ich persönlich für BDD eintrete, erfordern Ihre eigenen Geschäftsanforderungen möglicherweise etwas anderes für die Umstände Ihres Teams. Der Schlüssel ist jedoch zu vermeiden, dass Sie Ihr bestehendes System hinterfragen. Sie können Ihre vorhandenen Tests jederzeit mit ein paar Tests unter Verwendung einer anderen API unterstützen, aber ich würde auf keinen Fall empfehlen, einen umfangreichen Test neu zu schreiben, nur um alles gleich zu machen. Da veralteter Code nicht mehr verwendet wird, können Sie ihn und seine Tests einfach durch neuen Code und Tests mit einer alternativen API ersetzen, ohne dass Sie in einen großen Aufwand investieren müssen, der Ihnen nicht unbedingt einen echten geschäftlichen Nutzen bringt. Wie für die Verwendung einer Unit-Testing-API,
quelle
Was Sie haben, ist einfach und erledigt die Arbeit. Wenn es bei Ihnen funktioniert, großartig. Sie nicht brauchen einen Mainstream - Unit Testing Framework, und ich würde auf die Arbeit der Portierung eine bestehende Bibliothek von Unit - Tests zu einem neuen Rahmen gehen zögern. Ich denke, der größte Wert von Unit-Testing-Frameworks besteht darin, die Markteintrittsbarriere zu verringern. Sie schreiben gerade Tests, weil das Framework bereits vorhanden ist. Sie haben diesen Punkt überschritten, sodass Sie diesen Vorteil nicht erhalten.
Der andere Vorteil der Verwendung eines Mainstream-Frameworks - und es ist ein kleiner Vorteil, IMO - besteht darin, dass neue Entwickler möglicherweise bereits mit dem von Ihnen verwendeten Framework auf dem neuesten Stand sind und daher weniger Schulung benötigen. In der Praxis sollte dies mit einem einfachen Ansatz wie dem, den Sie beschrieben haben, keine große Sache sein.
Außerdem haben die meisten Mainstream-Frameworks bestimmte Funktionen, die Ihr Framework möglicherweise aufweist oder nicht. Diese Funktionen reduzieren den Installationscode und machen das Schreiben von Testfällen schneller und einfacher:
quelle