Ich bin ein relativ neuer Softwareentwickler, und eines der Dinge, die ich verbessern sollte, ist meine Fähigkeit, meinen eigenen Code zu testen. Wenn ich eine neue Funktionalität entwickle, finde ich es sehr schwierig, alle möglichen Pfade zu verfolgen, um Fehler zu finden. Ich neige dazu, dem Weg zu folgen, auf dem alles funktioniert. Ich weiß, dass dies ein bekanntes Problem ist, das Programmierer haben, aber bei meinem derzeitigen Arbeitgeber gibt es keine Tester, und meine Kollegen scheinen darin ziemlich gut zu sein.
In meiner Organisation führen wir weder testgetriebene Entwicklungen noch Unit-Tests durch. Es würde mir sehr helfen, aber es ist unwahrscheinlich, dass sich dies ändern wird.
Was glaubt ihr, könnte ich tun, um das zu überwinden? Welchen Ansatz verwenden Sie zum Testen Ihres eigenen Codes?
Antworten:
Die Aufgabe eines Programmierers ist es, Dinge zu bauen.
Die Aufgabe eines Testers ist es, Dinge zu zerbrechen.
Am schwierigsten ist es, Dinge zu zerbrechen, die Sie gerade gebaut haben. Sie werden nur dann erfolgreich sein, wenn Sie diese psychologische Barriere überwinden.
quelle
Franciso, ich werde hier einige Annahmen treffen, basierend auf dem, was du gesagt hast:
"Wir machen weder TDD noch Unit-Tests. Es würde mir sehr helfen, aber es ist unwahrscheinlich, dass sich dies ändern wird."
Ich vermute, dass Ihr Team nicht viel Wert auf Tests legt oder das Management keine Zeit einplanen wird, um zu versuchen, vorhandenen Code aufzuräumen und die technische Verschuldung auf ein Minimum zu beschränken.
Zunächst müssen Sie Ihr Team / Management vom Wert des Testens überzeugen. Sei diplomatisch. Wenn das Management Ihr Team in Bewegung hält, müssen Sie ihm einige Fakten zeigen, z. B. die Fehlerrate für jede Version. Die zur Behebung von Fehlern aufgewendete Zeit könnte besser für andere Aufgaben aufgewendet werden, z. B. die Verbesserung der Anwendung und ihre Anpassung an zukünftige Anforderungen.
Wenn das Team und das Management im Allgemeinen mit der Korrektur des Codes nicht einverstanden sind und Sie sich darüber unzufrieden fühlen, müssen Sie möglicherweise einen anderen Arbeitsplatz suchen, es sei denn, Sie können sie wie gesagt überzeugen. Ich bin diesem Problem in unterschiedlichem Maße an allen Orten begegnet, an denen ich gearbeitet habe. Es könnte alles Mögliche sein, vom Fehlen eines geeigneten Domänenmodells bis hin zur schlechten Kommunikation im Team.
Sich um Ihren Code und die Qualität des von Ihnen entwickelten Produkts zu kümmern, ist ein gutes Attribut, das Sie immer anderen Menschen empfehlen möchten.
quelle
Wenn Sie in C, Objective-C oder C ++ codieren, können Sie den statischen Analysator von CLang verwenden , um Ihre Quelle zu kritisieren, ohne sie tatsächlich auszuführen .
Es sind einige Tools zum Debuggen des Speichers verfügbar: ValGrind, Guard Malloc unter Mac OS X, Electric Fence unter * NIX.
Einige Entwicklungsumgebungen bieten die Möglichkeit, einen Debugging-Speicherzuweiser zu verwenden, der beispielsweise neu zugewiesene Seiten und neu freigegebene Seiten mit Müll füllt, die Freigabe nicht zugewiesener Zeiger erkennt und vor und nach jedem Heap-Block einige Daten schreibt, wobei der Debugger aktiv ist wird aufgerufen, wenn sich das bekannte Muster dieser Daten ändert.
Ein Typ von Slashdot sagte, er habe viel Wert darauf gelegt, in einem Debugger immer neue Quellen zu erschließen. "Das war's", sagte er. Ich folge nicht immer seinem Rat, aber wenn ich ihn habe, war er mir sehr hilfreich. Selbst wenn Sie keinen Testfall haben, der einen ungewöhnlichen Codepfad stimuliert, können Sie eine Variable in Ihrem Debugger so verändern, dass sie solche Pfade verwendet, indem Sie beispielsweise etwas Speicher zuweisen und dann mit dem Debugger den neuen Zeiger auf NULL anstelle von setzen Speicheradresse, dann schrittweise durch den Allokationsfehler-Handler.
Verwenden Sie Assertions - das assert () -Makro in C, C ++ und Objective-C. Wenn Ihre Sprache keine Assert-Funktion bietet, schreiben Sie selbst eine.
Verwenden Sie Asserts großzügig und lassen Sie sie dann in Ihrem Code. Ich nenne assert () "Der Test, der weiter testet". Ich benutze sie am häufigsten, um die Voraussetzungen am Einstiegspunkt der meisten meiner Funktionen zu überprüfen. Das ist ein Teil von "Programming by Contract", das in die Programmiersprache Eiffel integriert ist. Der andere Teil sind Nachbedingungen, dh die Verwendung von assert () an Funktionsrückgabepunkten, aber ich stelle fest, dass ich nicht so viele Meilen davon bekomme wie die Vorbedingungen.
Sie können assert auch verwenden, um Klasseninvarianten zu überprüfen. Während keine Klasse unbedingt eine Invariante haben muss, haben die vernünftigsten entworfenen Klassen diese. Eine Klasseninvariante ist eine Bedingung, die immer wahr ist, außer innerhalb von Elementfunktionen, die Ihr Objekt vorübergehend in einen inkonsistenten Zustand versetzen können. Solche Funktionen müssen immer die Konsistenz wiederherstellen, bevor sie zurückkehren.
Auf diese Weise kann jede Mitgliedsfunktion die Invariante beim Ein- und Ausstieg überprüfen und die Klasse kann eine Funktion namens CheckInvariant definieren, die jeder andere Code jederzeit aufrufen kann.
Verwenden Sie ein Tool zur Codeabdeckung, um zu überprüfen, welche Zeilen Ihrer Quelle tatsächlich getestet werden, und entwerfen Sie dann Tests, die die nicht getesteten Zeilen stimulieren. Zum Beispiel könnten Sie Handler für wenig Arbeitsspeicher überprüfen, indem Sie Ihre App in einer VM ausführen, die mit wenig physischem Arbeitsspeicher und entweder keiner oder einer sehr kleinen Auslagerungsdatei konfiguriert ist.
(Aus irgendeinem Grund war ich nie mit BeOS vertraut, obwohl das BeOS ohne Auslagerungsdatei ausgeführt werden konnte, war es auf diese Weise äußerst instabil. Dominic Giampaolo, der das BFS-Dateisystem schrieb, forderte mich auf, das BeOS niemals ohne Auslagerungsdatei auszuführen. Ich nicht sehen, warum das wichtig sein sollte, aber es muss eine Art Implementierungsartefakt gewesen sein.)
Sie sollten auch die Antwort Ihres Codes auf E / A-Fehler testen. Versuchen Sie, alle Ihre Dateien auf einer Netzwerkfreigabe zu speichern, und trennen Sie dann das Netzwerkkabel, während Ihre App stark ausgelastet ist. Trennen Sie in ähnlicher Weise das Kabel oder schalten Sie das WLAN aus, wenn Sie über ein Netzwerk kommunizieren.
Besonders ärgerlich finde ich Websites, die keinen robusten Javascript-Code haben. Facebooks Seiten laden Dutzende kleiner Javascript-Dateien, aber wenn eine davon nicht heruntergeladen werden kann, bricht die ganze Seite. Es muss nur eine Möglichkeit geben, um eine Fehlertoleranz zu gewährleisten, beispielsweise durch einen erneuten Download, oder um einen angemessenen Fallback bereitzustellen, wenn einige Ihrer Skripte nicht heruntergeladen wurden.
Versuchen Sie, Ihre App mit dem Debugger oder mit "kill -9" auf * NIX zu beenden, während gerade eine große, wichtige Datei geschrieben wird. Wenn Ihre App über eine gute Architektur verfügt, wird die gesamte Datei geschrieben oder gar nicht, oder wenn sie nur teilweise geschrieben wird, wird das, was geschrieben wird, nicht beschädigt, und die gespeicherten Daten können vollständig verwendet werden die App beim erneuten Lesen der Datei.
Datenbanken haben immer fehlertolerante Festplatten-E / A, aber kaum eine andere Art von App. Aufgezeichnete Dateisysteme verhindern zwar eine Beschädigung des Dateisystems bei Stromausfall oder Abstürzen, verhindern jedoch keinesfalls die Beschädigung oder den Verlust von Endbenutzerdaten. Dies liegt in der Verantwortung der Benutzeranwendungen, aber kaum eine andere als Datenbanken implementieren Fehlertoleranz.
quelle
Wenn ich meinen Code teste, gehe ich normalerweise eine Reihe von Denkprozessen durch:
Der einfachste Weg, dies zu tun, besteht darin, meine Tests zusammen mit meinem Code zu entwickeln. Sobald ich auch nur ein Codefragment geschrieben habe, schreibe ich gerne einen Test dafür. Der Versuch, alle Tests durchzuführen, nachdem mehrere tausend Codezeilen mit nicht trivialer zyklomatischer Codekomplexität codiert wurden, ist ein Albtraum. Das Hinzufügen von ein oder zwei weiteren Tests nach dem Hinzufügen einiger Codezeilen ist wirklich einfach.
Übrigens, nur weil das Unternehmen, in dem Sie arbeiten, und / oder Ihre Kollegen keine Unit-Tests oder TDD durchführen, heißt das nicht, dass Sie sie nicht testen können, es sei denn, sie sind ausdrücklich verboten. Vielleicht ist es ein gutes Beispiel für andere, sie zum Erstellen robusten Codes zu verwenden.
quelle
Zusätzlich zu den Ratschlägen in den anderen Antworten würde ich die Verwendung von statischen Analysetools vorschlagen (Wikipedia hat eine Liste mit einer Reihe von statischen Analysetools für verschiedene Sprachen ), um potenzielle Fehler zu finden, bevor mit dem Testen begonnen wird, sowie die Überwachung einiger Metriken, die sich auf diese beziehen Die Testbarkeit von Code wie zyklomatische Komplexität , Halstead-Komplexitätsmessungen sowie Kohäsion und Kopplung (Sie können diese mit Fan-In und Fan-Out messen).
Wenn Sie feststellen, dass Code nur schwer zu testen und leichter zu testen ist, können Sie leichter Testfälle schreiben. Auch das frühzeitige Erkennen von Fehlern erhöht den Wert Ihrer gesamten Qualitätssicherungspraktiken (einschließlich Tests). Wenn Sie sich von hier aus mit Unit-Test- und Spott-Tools vertraut machen, können Sie Ihre Tests einfacher implementieren.
quelle
Sie können die mögliche Verwendung von Wahrheitstabellen untersuchen , um alle potenziellen Pfade in Ihrem Code zu definieren. Es ist unmöglich, alle Möglichkeiten in komplexen Funktionen zu berücksichtigen, aber wenn Sie Ihre Behandlung für alle bekannten Pfade eingerichtet haben, können Sie eine Behandlung für den else-Fall einrichten.
Der größte Teil dieser besonderen Fähigkeit wird jedoch durch Erfahrung erlernt. Nachdem Sie über einen längeren Zeitraum ein bestimmtes Framework verwendet haben, werden die Verhaltensmuster und -merkmale angezeigt, anhand derer Sie einen Codeabschnitt betrachten und feststellen können, wo eine kleine Änderung zu einem schwerwiegenden Fehler führen kann. Die einzige Möglichkeit, die ich mir vorstellen kann, um Ihre Fähigkeiten in diesem Bereich zu verbessern, ist das Üben.
quelle
Wenn, wie Sie sagten, Sie keine Unit-Tests benötigen, gibt es keinen besseren Ansatz als den Versuch, Ihren eigenen Code manuell zu knacken.
Versuchen Sie , Ihren Code an die Grenzen zu bringen . Versuchen Sie beispielsweise, Variablen an eine Funktion zu übergeben, die die Grenzwerte überschreitet. Haben Sie eine Funktion, die Benutzereingaben filtern soll? Versuchen Sie, verschiedene Zeichenkombinationen einzugeben.
Betrachten Sie den Standpunkt des Benutzers . Versuchen Sie, einer der Benutzer zu sein, die Ihre Anwendung oder Funktionsbibliothek verwenden.
quelle
Ihre Kollegen müssen wirklich außergewöhnlich sein, um TDD- oder Unit-Tests nicht zu befolgen und niemals Fehler zu generieren. Ich bezweifle, dass sie selbst keine Unit-Tests durchführen.
Ich nehme an, dass Ihre Kollegen mehr Tests durchführen, als zugelassen werden. Da diese Tatsache jedoch dem Management nicht bekannt ist, leidet die Organisation darunter, dass das Management den Eindruck hat, dass keine echten Tests durchgeführt werden und die Anzahl der Fehler daher gering ist Das Testen ist unwichtig und die Zeit dafür ist nicht vorgesehen.
Sprechen Sie mit Ihren Kollegen und versuchen Sie herauszufinden, welche Art von Unit-Tests sie durchführen, und emulieren Sie dies. Zu einem späteren Zeitpunkt können Sie bessere Prototypen für Unit-Test- und TDD-Attribute erstellen und dem Team diese Konzepte zur einfacheren Übernahme langsam vorstellen.
quelle
Sie sollten in der Lage sein, Berichterstattung über das zu erhalten, was Sie schreiben, auch wenn Ihre Organisation nicht über vollständige Berichterstattung verfügt. Wie so viele Dinge in der Programmierung ist die Erfahrung, es immer wieder zu tun, eine der besten Möglichkeiten, um darin effizient zu sein.
quelle
Zusätzlich zu all den anderen Kommentaren sollten Ihre Kollegen, da Sie sagen, dass sie gut darin sind, Tests zu schreiben, bei denen es sich nicht um Happy-Path-Tests handelt, sie bitten, sich mit Ihnen zu paaren, um einige Tests zu schreiben.
Am besten lernen Sie, wie es gemacht wird und was Sie daraus lernen.
quelle
Black-Box-Test! Sie sollten Ihre Klassen / Methoden mit Blick auf das Testen erstellen. Ihre Tests sollten auf der Spezifikation der Software basieren und in Ihrem Sequenzdiagramm (über Anwendungsfälle) klar definiert sein.
Jetzt, da Sie möglicherweise keine testgetriebene Entwicklung durchführen möchten ...
Setzen Sie die Eingabevalidierung auf alle eingehenden Daten. Vertraue niemandem. Das .net-Framework löst viele Ausnahmen aus, die auf ungültigen Argumenten, Nullreferenzen und ungültigen Zuständen basieren. Sie sollten bereits darüber nachdenken, die Eingabevalidierung auf der Benutzeroberflächenebene zu verwenden, damit es in der Middleware der gleiche Trick ist.
Aber Sie sollten wirklich eine Art automatisiertes Testen durchführen. das Zeug rettet Leben.
quelle
Durch meine Erfahrung
Testeinheit, wenn es nicht vollautomatisch ist, ist es unbrauchbar. Es ist eher so, als ob ein Spitzhaariger Chef es kaufen könnte. Warum ?, weil Test Unit Ihnen versprochen hat, Zeit (und Geld) zu sparen, um einige Testprozesse zu automatisieren. Einige Test-Unit-Tools tun jedoch das Gegenteil. Sie zwingen Programmierer, auf seltsame Weise zu arbeiten, und zwingen andere, übermäßige Tests zu erstellen. In den meisten Fällen wird keine Arbeitsstunde gespart, sondern die Umsetzungszeit von der Qualitätssicherung zum Entwickler verlängert.
UML ist eine andere Zeitverschwendung. Ein einzelnes Whiteboard + Stift kann dasselbe leisten, und das kostengünstiger und schneller.
Übrigens: Wie kann man gut codieren (und Fehler vermeiden)?
a) Atomizität. Eine Funktion, die eine einfache (oder einige einzelne) Aufgabe erledigt. Weil es leicht zu verstehen ist, ist es leicht zu verfolgen und leicht zu lösen.
b) Homologie. Wenn Sie beispielsweise eine Datenbank mit einer Speicherprozedur aufrufen, machen Sie dies für den Rest des Codes.
c) Identifizieren, Reduzieren und Isolieren von "Creative Code". Der größte Teil des Codes besteht aus Kopieren und Einfügen. Creative-Code ist das Gegenteil, ein Code, der neu ist und als Prototyp fungiert. Er kann fehlschlagen. Dieser Code ist anfällig für Logikfehler, daher ist es wichtig, ihn zu reduzieren, zu isolieren und zu identifizieren.
d) "Thin Ice" -Code ist der Code, von dem Sie wissen, dass er "falsch" (oder potenziell gefährlich) ist, der jedoch weiterhin benötigt wird, z. B. unsicheren Code für einen Multitask-Prozess. Vermeiden Sie, wenn Sie können.
e) Vermeiden Sie Black-Box-Code, einschließlich Code, den Sie nicht verwenden (z. B. Framework), und regulären Ausdruck. Es ist leicht, einen Fehler mit dieser Art von Code zu übersehen. Ich habe zum Beispiel in einem Projekt mit Jboss gearbeitet und in Jboss (mit der neuesten stabilen Version) nicht einen, sondern 10 Fehler gefunden. Es war eine PITA, diese zu finden. Vermeiden Sie besonders Ruhezustand, es versteckt die Implementierung, daher die Fehler.
f) füge Kommentare in deinen Code ein.
g) Benutzereingaben als Fehlerquelle. identifiziere es. Beispielsweise wird SQL Injection durch eine Benutzereingabe verursacht.
h) Identifizieren Sie ein schlechtes Element des Teams und trennen Sie die zugewiesene Aufgabe. Einige Programmierer neigen dazu, den Code zu verfälschen.
i) Vermeiden Sie unnötigen Code. Wenn die Klasse beispielsweise ein Interface benötigt, verwenden Sie es, andernfalls fügen Sie keinen irrelevanten Code hinzu.
a) und b) sind Schlüssel. Zum Beispiel hatte ich ein Problem mit einem System, als ich auf eine Schaltfläche (Speichern) klickte, wurde das Formular nicht gespeichert. Dann habe ich eine Checkliste gemacht:
Und eine Randnotiz
quelle
Ein Tester und ein Programmierer sehen sich dem Problem aus verschiedenen Blickwinkeln gegenüber, aber beide Rollen sollten die Funktionalität vollständig testen und Fehler finden. Wo sich die Rollen unterscheiden, ist im Fokus. Ein klassischer Tester sieht die Anwendung nur von außen (Black Box). Sie sind Experten für die funktionalen Anforderungen der App. Von einem Programmierer wird erwartet, dass er sich sowohl mit den funktionalen Anforderungen als auch mit dem Code auskennt (sich jedoch eher auf den Code konzentriert).
(Es hängt von der Organisation ab, ob von Programmierern ausdrücklich erwartet wird, dass sie Experten für Anforderungen sind. Unabhängig davon besteht die implizite Erwartung, dass Sie - nicht die Person, die die Anforderungen erfüllt - die Schuld tragen, wenn Sie etwas falsches entwerfen.)
Diese Doppelexpertenrolle belastet den Programmierer und kann, abgesehen von den erfahrensten, die Kompetenz in Bezug auf Anforderungen verringern. Ich stelle fest, dass ich mental den Gang wechseln muss, um die Benutzer der Anwendung zu berücksichtigen. Folgendes hilft mir:
quelle
Ich denke, Sie wollen an zwei Fronten arbeiten. Eine davon ist politisch und veranlasst Ihre Organisation, Tests auf einer bestimmten Ebene durchzuführen (mit der Hoffnung, dass sie im Laufe der Zeit mehr übernehmen werden). Sprechen Sie mit Qualitätssicherungsingenieuren außerhalb Ihres Arbeitsplatzes. Hier finden Sie Listen mit QS-Büchern . Stöbern Sie in relevanten Wikipedia-Artikeln . Machen Sie sich mit den QS-Grundsätzen und -Praktiken vertraut. Das Erlernen dieses Materials bereitet Sie darauf vor, den überzeugendsten Fall in Ihrem Unternehmen zu machen. Es gibt gute QS-Abteilungen, die ihren Organisationen einen erheblichen Mehrwert bieten.
Nehmen Sie als einzelner Entwickler Strategien an, die Sie in Ihrer eigenen Arbeit anwenden können. Verwenden Sie TDD selbst, indem Sie Code und Tests gemeinsam entwickeln. Halten Sie die Tests klar und gut gepflegt. Wenn Sie gefragt werden, warum Sie dies tun, können Sie sagen, dass Sie Regressionen verhindern und Ihr Denkprozess besser organisiert ist (beides wird zutreffen). Es ist eine Kunst, testbaren Code zu schreiben , ihn zu lernen. Seien Sie ein gutes Beispiel für Ihre Mitentwickler.
Teilweise predige ich mir hier, weil ich viel weniger von diesem Zeug mache, als ich weiß, dass ich sollte.
quelle