tl; dr
Bei Pivotal haben wir Cedar geschrieben, weil wir Rspec für unsere Ruby-Projekte verwenden und lieben. Cedar soll OCUnit nicht ersetzen oder mit ihm konkurrieren. Es soll die Möglichkeit des Testens im BDD-Stil für Objective C bieten, genau wie Rspec Pionierarbeit beim Testen im BDD-Stil in Ruby geleistet hat, aber Test :: Unit nicht eliminiert hat. Die Wahl des einen oder anderen hängt weitgehend von den Stilvorlieben ab.
In einigen Fällen haben wir Cedar entwickelt, um einige Mängel bei der Funktionsweise von OCUnit zu beheben. Insbesondere wollten wir den Debugger in Tests verwenden, Tests über die Befehlszeile und in CI-Builds ausführen und nützliche Textausgaben für Testergebnisse erhalten. Diese Dinge können für Sie mehr oder weniger nützlich sein.
Lange Antwort
Die Entscheidung zwischen zwei Test-Frameworks wie Cedar und OCUnit (zum Beispiel) hängt von zwei Dingen ab: dem bevorzugten Stil und der Benutzerfreundlichkeit. Ich werde mit dem Stil beginnen, denn das ist einfach eine Frage der Meinung und der Präferenz. Benutzerfreundlichkeit ist in der Regel eine Reihe von Kompromissen.
Stilüberlegungen gehen über die von Ihnen verwendete Technologie oder Sprache hinaus. xUnit-artige Unit-Tests gibt es schon viel länger als BDD-artige Tests, aber letztere haben schnell an Popularität gewonnen, hauptsächlich aufgrund von Rspec.
Der Hauptvorteil von Tests im xUnit-Stil ist die Einfachheit und breite Akzeptanz (bei Entwicklern, die Komponententests schreiben). Fast jede Sprache, in der Sie Code schreiben könnten, verfügt über ein Framework im xUnit-Stil.
Frameworks im BDD-Stil weisen im Vergleich zum xUnit-Stil in der Regel zwei Hauptunterschiede auf: die Strukturierung des Tests (oder der Spezifikationen) und die Syntax zum Schreiben Ihrer Aussagen. Für mich ist der strukturelle Unterschied das Hauptunterscheidungsmerkmal. xUnit-Tests sind eindimensional mit einer setUp-Methode für alle Tests in einer bestimmten Testklasse. Die Klassen, die wir testen, sind jedoch nicht eindimensional. Wir müssen häufig Aktionen in verschiedenen, möglicherweise widersprüchlichen Kontexten testen. Betrachten Sie beispielsweise eine einfache ShoppingCart-Klasse mit einer addItem: -Methode (für die Zwecke dieser Antwort verwende ich die Objective C-Syntax). Das Verhalten dieser Methode kann sich unterscheiden, wenn der Einkaufswagen leer ist, im Vergleich dazu, wenn der Einkaufswagen andere Artikel enthält. Dies kann abweichen, wenn der Benutzer einen Rabattcode eingegeben hat. es kann abweichen, wenn der angegebene Artikel ' t mit der ausgewählten Versandart versendet werden; usw. Da sich diese möglichen Bedingungen überschneiden, ergibt sich eine geometrisch zunehmende Anzahl möglicher Kontexte. Beim Testen im xUnit-Stil führt dies häufig zu vielen Methoden mit Namen wie testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. Die Struktur von Frameworks im BDD-Stil ermöglicht es Ihnen, diese Bedingungen individuell zu organisieren. Dies erleichtert es mir, sicherzustellen, dass ich alle Fälle abdeckte, und es ist einfacher, einzelne Bedingungen zu finden, zu ändern oder hinzuzufügen. Bei Verwendung der Cedar-Syntax sieht die obige Methode beispielsweise folgendermaßen aus: Beim Testen im xUnit-Stil führt dies häufig zu vielen Methoden mit Namen wie testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. Die Struktur von Frameworks im BDD-Stil ermöglicht es Ihnen, diese Bedingungen individuell zu organisieren. Dies erleichtert es mir, sicherzustellen, dass ich alle Fälle abdeckte, und es ist einfacher, einzelne Bedingungen zu finden, zu ändern oder hinzuzufügen. Bei Verwendung der Cedar-Syntax sieht die obige Methode beispielsweise folgendermaßen aus: Beim Testen im xUnit-Stil führt dies häufig zu vielen Methoden mit Namen wie testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. Die Struktur von Frameworks im BDD-Stil ermöglicht es Ihnen, diese Bedingungen individuell zu organisieren. Dies erleichtert es mir, sicherzustellen, dass ich alle Fälle abdeckte, und es ist einfacher, einzelne Bedingungen zu finden, zu ändern oder hinzuzufügen. Bei Verwendung der Cedar-Syntax sieht die obige Methode beispielsweise folgendermaßen aus:
describe(@"ShoppingCart", ^{
describe(@"addItem:", ^{
describe(@"when the cart is empty", ^{
describe(@"with no discount code", ^{
describe(@"when the shipping method applies to the item", ^{
it(@"should add the item to the cart", ^{
...
});
it(@"should add the full price of the item to the overall price", ^{
...
});
});
describe(@"when the shipping method does not apply to the item", ^{
...
});
});
describe(@"with a discount code", ^{
...
});
});
describe(@"when the cart contains other items, ^{
...
});
});
});
In einigen Fällen finden Sie Kontexte, die dieselben Sätze von Zusicherungen enthalten, die Sie mithilfe gemeinsam genutzter Beispielkontexte austrocknen können.
Der zweite Hauptunterschied zwischen Frameworks im BDD-Stil und Frameworks im xUnit-Stil, die Assertions- (oder "Matcher") - Syntax, macht den Stil der Spezifikationen einfach etwas schöner. Manche Leute mögen es wirklich, andere nicht.
Das führt zur Frage der Benutzerfreundlichkeit. In diesem Fall hat jedes Framework seine Vor- und Nachteile:
OCUnit gibt es schon viel länger als Cedar und ist direkt in Xcode integriert. Dies bedeutet, dass es einfach ist, ein neues Testziel zu erstellen, und dass es meistens "einfach funktioniert", Tests zum Laufen zu bringen. Auf der anderen Seite stellten wir fest, dass es in einigen Fällen, beispielsweise auf einem iOS-Gerät, nahezu unmöglich war, OCUnit-Tests zum Laufen zu bringen. Das Einrichten von Cedar-Spezifikationen erfordert mehr Arbeit als OCUnit-Tests, da Sie die Bibliothek selbst abgerufen und mit ihr verknüpft haben (in Xcode nie eine triviale Aufgabe). Wir arbeiten daran, die Einrichtung zu vereinfachen, und Vorschläge sind mehr als willkommen.
OCUnit führt Tests als Teil des Builds aus. Dies bedeutet, dass Sie keine ausführbare Datei ausführen müssen, damit Ihre Tests ausgeführt werden. Wenn Tests fehlschlagen, schlägt Ihr Build fehl. Dies vereinfacht das Ausführen von Tests in einem Schritt und die Testausgabe wird direkt in Ihr Build-Ausgabefenster verschoben, sodass Sie sie leicht sehen können. Wir haben uns aus mehreren Gründen dafür entschieden, Cedar-Spezifikationen in eine ausführbare Datei zu integrieren, die Sie separat ausführen:
- Wir wollten den Debugger verwenden können. Sie führen Cedar-Spezifikationen wie jede andere ausführbare Datei aus, sodass Sie den Debugger auf die gleiche Weise verwenden können.
- Wir wollten eine einfache Anmeldung der Konsole in Tests. Sie können NSLog () in OCUnit-Tests verwenden, aber die Ausgabe wird in das Erstellungsfenster verschoben, in dem Sie den Erstellungsschritt entfalten müssen, um ihn lesen zu können.
- Wir wollten einfach zu lesende Testberichte, sowohl in der Befehlszeile als auch in Xcode. OCUnit-Ergebnisse werden in Xcode gut im Build-Fenster angezeigt, aber das Erstellen über die Befehlszeile (oder als Teil eines CI-Prozesses) führt zu einer Testausgabe, die mit vielen anderen Build-Ausgaben vermischt ist. Mit getrennten Build- und Run-Phasen trennt Cedar die Ausgabe, sodass die Testausgabe leicht zu finden ist. Der Standard-Cedar-Testläufer kopiert den Standarddruckstil "." für jede übergebene Spezifikation "F" für fehlerhafte Spezifikationen usw. Cedar kann auch benutzerdefinierte Reporterobjekte verwenden, sodass Sie die Ergebnisse mit ein wenig Aufwand nach Belieben ausgeben können.
OCUnit ist das offizielle Unit-Testing-Framework für Objective C und wird von Apple unterstützt. Apple verfügt im Grunde über unbegrenzte Ressourcen. Wenn also etwas erledigt werden soll, wird es erledigt. Und schließlich ist dies Apples Sandbox, in der wir spielen. Die Kehrseite dieser Medaille ist jedoch, dass Apple jeden Tag in der Größenordnung von Bajillion Supportanfragen und Fehlerberichten erhält. Sie sind bemerkenswert gut darin, sie alle zu behandeln, aber sie sind möglicherweise nicht in der Lage, Probleme zu behandeln, die Sie sofort oder überhaupt melden. Cedar ist viel neuer und weniger gebacken als OCUnit. Wenn Sie jedoch Fragen, Probleme oder Vorschläge haben, senden Sie eine Nachricht an die Cedar-Mailingliste (cedar-discuss@googlegroups.com). Wir werden alles tun, um Ihnen zu helfen. Sie können auch den Code von Github (github.com/pivotal/cedar) abspalten und hinzufügen, was Ihrer Meinung nach fehlt.
Das Ausführen von OCUnit-Tests auf iOS-Geräten kann schwierig sein. Ehrlich gesagt habe ich dies seit einiger Zeit nicht mehr versucht, daher ist es vielleicht einfacher geworden, aber als ich es das letzte Mal versuchte, konnte ich einfach keine OCUnit-Tests für eine UIKit-Funktionalität durchführen. Als wir Cedar geschrieben haben, haben wir sichergestellt, dass wir UIKit-abhängigen Code sowohl auf dem Simulator als auch auf Geräten testen können.
Schließlich haben wir Cedar für Unit-Tests geschrieben, was bedeutet, dass es nicht wirklich mit Projekten wie UISpec vergleichbar ist. Es ist schon eine Weile her, dass ich versucht habe, UISpec zu verwenden, aber ich habe verstanden, dass es sich hauptsächlich darauf konzentriert, die Benutzeroberfläche auf einem iOS-Gerät programmgesteuert zu steuern. Wir haben uns ausdrücklich dafür entschieden, Cedar nicht zu veranlassen, diese Art von Spezifikationen zu unterstützen, da Apple (zu diesem Zeitpunkt) UIAutomation ankündigen wollte.