Sie finden eine endlose Liste von Blogs, Artikeln und Websites, die die Vorteile des Unit-Tests Ihres Quellcodes fördern . Es ist fast garantiert, dass die Entwickler, die die Compiler für Java, C ++, C # und andere typisierte Sprachen programmiert haben, Unit-Tests verwendet haben, um ihre Arbeit zu verifizieren.
Warum fehlt dann, trotz seiner Popularität, das Testen in der Syntax dieser Sprachen?
Microsoft hat LINQ für C # eingeführt . Warum konnten sie also keine Tests hinzufügen?
Ich möchte nicht vorhersagen, wie sich diese Sprachänderungen auswirken würden, sondern klären, warum sie zunächst fehlen.
Als Beispiel: Wir wissen, dass Sie eine for
Schleife ohne die Syntax der for
Anweisung schreiben können . Sie könnten while
oder if
/ goto
Anweisungen verwenden. Jemand fand eine for
Aussage effizienter und führte sie in eine Sprache ein.
Warum haben die Tests nicht dieselbe Entwicklung der Programmiersprachen verfolgt?
quelle
Antworten:
Unit-Tests werden, wie so oft, am besten auf Bibliotheksebene und nicht auf Sprachebene unterstützt. Insbesondere verfügt C # über zahlreiche Unit Testing-Bibliotheken sowie über systemeigene Funktionen wie .NET Framework
Microsoft.VisualStudio.TestTools.UnitTesting
.Jede Unit Testing-Bibliothek hat eine etwas andere Testphilosophie und -syntax. Wenn alle Dinge gleich sind, sind mehr Entscheidungen besser als weniger. Wenn Komponententests in die Sprache eingebunden wären, wären Sie entweder an die Auswahl des Sprachdesigners gebunden, oder Sie würden ... eine Bibliothek verwenden und die Sprachtestfunktionen vollständig vermeiden.
Beispiele
Nunit - Allzweckframework für idiomatische Komponententests , das die Sprachfunktionen von C # voll ausnutzt.
Moq - Verspottendes Framework, das Lambda-Ausdrücke und Ausdrucksbäume ohne Aufnahme- / Wiedergabemetapher voll ausnutzt.
Es gibt viele andere Möglichkeiten. Bibliotheken wie Microsoft Fakes können "Shims ..." - Mocks erstellen, bei denen Sie Ihre Klassen nicht mithilfe von Schnittstellen oder virtuellen Methoden schreiben müssen.
Linq ist kein Sprachfeature (trotz seines Namens)
Linq ist eine Bibliotheksfunktion. Wir haben viele neue Funktionen in der C # -Sprache kostenlos, wie Lambda-Ausdrücke und Erweiterungsmethoden, aber die eigentliche Implementierung von Linq ist in .NET Framework.
Es gibt einige syntaktische Zucker, die C # hinzugefügt wurden, um die Linq-Anweisungen sauberer zu machen, aber dieser Zucker ist nicht erforderlich, um Linq zu verwenden.
quelle
var
Schlüsselwort :)Es gibt viele Gründe. Eric Lippert hat viele Male angegeben, dass der Grund
feature X
nicht in C # liegt, weil es einfach nicht in ihrem Budget ist. Sprachdesigner haben weder unendlich viel Zeit noch Geld, um Dinge zu implementieren, und mit jeder neuen Funktion sind Wartungskosten verbunden. Die Sprache so klein wie möglich zu halten, ist nicht nur für die Sprachdesigner einfacher - es ist auch für jeden einfacher, alternative Implementierungen und Tools (z. B. IDEs) zu schreiben Portabilität kostenlos. Wenn Unit-Tests als Bibliothek implementiert werden, müssen Sie sie nur einmal schreiben, und sie funktionieren bei jeder konformen Implementierung der Sprache.Es ist erwähnenswert, dass D Unterstützung auf Syntaxebene für Komponententests bietet . Ich weiß nicht, warum sie sich dazu entschlossen haben, dies zu tun, aber es ist erwähnenswert, dass D eine "Programmiersprache für Systeme auf hohem Niveau" sein soll. Die Designer wollten, dass es für die Art von unsicherem, einfachem Code, für den C ++ traditionell verwendet wurde, brauchbar ist, und ein Fehler in unsicherem Code ist unglaublich kostspielig - undefiniertes Verhalten. Ich nehme an, es hat für sie Sinn gemacht, zusätzliche Anstrengungen zu unternehmen, um zu überprüfen, ob ein unsicherer Code funktioniert. Beispielsweise können Sie erzwingen, dass nur bestimmte vertrauenswürdige Module unsichere Vorgänge wie ungeprüfte Arrayzugriffe oder Zeigerarithmetik ausführen können.
Die schnelle Entwicklung war auch für sie ein wichtiges Anliegen, sodass D-Code so schnell kompiliert werden konnte, dass er als Skriptsprache verwendet werden konnte. Backeinheitentests direkt in die Sprache, sodass Sie Ihre Tests ausführen können, indem Sie einfach ein zusätzliches Flag an den Compiler übergeben.
Ich denke jedoch, dass eine großartige Unit-Testing-Bibliothek viel mehr kann, als nur einige Methoden zu finden und auszuführen. Nehmen Sie zum Beispiel Haskells QuickCheck , mit dem Sie Dinge wie "für alle x und y
f (x, y) == f (y, x)
" testen können . QuickCheck ist besser als Unit-Test- Generator zu bezeichnen und ermöglicht das Testen von Dingen auf einer höheren Ebene als "Für diesen Eingang erwarte ich diesen Ausgang". QuickCheck und Linq unterscheiden sich nicht sonderlich - sie sind beide domänenspezifische Sprachen. Anstatt die Unterstützung von Unit-Tests auf eine Sprache zu beschränken, sollten Sie die Funktionen hinzufügen, die erforderlich sind, um DSLs praktisch zu machen. Sie werden nicht nur Unit-Tests erhalten, sondern auch eine bessere Sprache.quelle
Denn das Testen und insbesondere das testgetriebene Entwickeln ist ein zutiefst kontraintuitives Phänomen.
Fast jeder Programmierer beginnt seine Karriere mit der Überzeugung, dass er die Komplexität viel besser beherrscht als sie tatsächlich ist. Die Tatsache, dass selbst der größte Programmierer keine großen und komplexen Programme ohne schwerwiegende Fehler schreiben kann, wenn er nicht viele Regressionstests verwendet, ist für viele Praktiker ernsthaft enttäuschend und sogar beschämend. Daher die vorherrschende Abneigung gegen regelmäßige Tests auch bei Fachleuten, die es schon besser wissen sollten.
Ich denke, die Tatsache, dass religiöse Tests sich langsam mehr durchsetzen und erwartet werden, ist größtenteils auf die Tatsache zurückzuführen, dass mit der Explosion der Speicherkapazität und der Rechenleistung größere Systeme als je zuvor gebaut werden - und dass extrem große Systeme besonders anfällig für Komplexität sind kann nicht ohne das Sicherheitsnetz der Regressionstests verwaltet werden. Infolgedessen geben selbst besonders hartnäckige und getäuschte Entwickler jetzt widerwillig zu, dass sie Tests benötigen und dies auch immer tun müssen (wenn dies wie ein Geständnis bei einem AA-Meeting klingt, ist dies durchaus beabsichtigt - ein Sicherheitsnetz zu benötigen, ist für viele psychologisch schwierig zuzugeben Einzelpersonen).
Die meisten heute populären Sprachen stammen aus der Zeit vor dieser Einstellungsänderung, daher haben sie wenig eingebaute Unterstützung für Tests: Sie haben
assert
, aber keine Verträge. Ich bin mir ziemlich sicher, dass zukünftige Sprachen, wenn der Trend anhält, mehr Unterstützung für die Sprache als für die Bibliotheksebene haben werden.quelle
Viele Sprachen unterstützen das Testen. Die Aussagen von C sind Tests, bei denen das Programm fehlschlagen kann. Hier hören die meisten Sprachen auf, aber Eiffel und in jüngerer Zeit Ada 2012 haben Vorvarianten (Dinge, die die Argumente für eine Funktion übergeben müssen) und Nachvarianten (Dinge, die die Ausgabe einer Funktion übergeben muss), wobei Ada die Möglichkeit bietet, auf die anfänglichen Argumente in der zu verweisen postinvariant. Ada 2012 bietet auch Typinvarianten. Wenn eine Methode für eine Ada-Klasse aufgerufen wird, wird die Typinvariante vor der Rückgabe überprüft.
Das ist nicht die Art von vollständigen Tests, die ein gutes Test-Framework für Sie bereitstellen kann, aber es ist eine wichtige Art von Tests, die Sprachen am besten unterstützen können.
quelle
Einige Befürworter stark typisierter funktionaler Sprachen würden argumentieren, dass diese Sprachmerkmale die Notwendigkeit von Komponententests verringern oder eliminieren.
Zwei, imho, ein gutes Beispiel dafür ist von F # for Fun and Profit hier und hier
Persönlich glaube ich immer noch an den Wert von Komponententests, aber es gibt einige gültige Punkte. Wenn beispielsweise ein illegaler Zustand im Code nicht darstellbar ist, ist es nicht nur unnötig, einen Komponententest für diesen Fall zu schreiben, sondern auch unmöglich.
quelle
Ich würde argumentieren, dass Sie das Hinzufügen einiger der erforderlichen Funktionen verpasst haben, weil sie nicht wie beim Komponententest hervorgehoben wurden .
Zum Beispiel werden Unit-Tests in C # hauptsächlich durch die Verwendung von Attributen gesteuert. Die Funktion " Benutzerdefinierte Attribute" bietet einen umfangreichen Erweiterungsmechanismus, mit dem Frameworks wie NUnit iterieren und konkurrieren können, beispielsweise mit theoretischen und parametrisierten Tests.
Dies bringt mich zu meinem zweiten Hauptpunkt - wir wissen nicht genug darüber, was eine gute Testbarkeit ausmacht, um es in eine Sprache zu backen. Das Innovationstempo beim Testen ist viel schneller als bei anderen Sprachkonstruktionen. Daher benötigen wir flexible Mechanismen in unseren Sprachen, um die Innovationsfreiheit zu gewährleisten.
Ich bin ein Benutzer, aber kein Fan von TDD - es ist in einigen Fällen sehr hilfreich, insbesondere um Ihr Design-Denken zu verbessern. Es ist nicht unbedingt nützlich für größere Legacy-Systeme - Tests auf höherer Ebene mit guten Daten und Automatisierung werden wahrscheinlich zusammen mit einer starken Code-Inspektionskultur mehr Nutzen bringen .
Andere relevante Lesung:
quelle