Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Tatsächlicher Nutzen von Unit-Tests [und TDD]
zero_x
myCSharp.de - Member

Avatar #avatar-2567.gif


Dabei seit:
Beiträge: 1069
Herkunft: Koblenz

beantworten | zitieren | melden

Hallo Golo Roden,

die Gedanken, die du vor neun Montaten hattest, habe ich gerade. Ich sehe - wie du auch sagtest - keine Vorteile von TDD bzw. Unittests. Der Sinneswandel, der dich getrieben hat, würde mich genauer interessieren. Du hast deinen Sinneswandel nur sehr oberflächlich beschrieben. Schon vorher wusstetst du, dass TDD Vorteile hat, hast dies aber nicht angewand. Da muss ja irgendwo ein Punkt sein, wo du sagtest, dass du TDD nun anwendest. In deinem letzen Satz sagtest du sogar "Insofern: TDD? Nie mehr ohne :-)!".

zero_x
zero_x | myCSharp.de - gemeinsam mehr erreichen

Für längere Zeit inaktiv.
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

Ich glaube der Punkt Refactoring ist an der stelle besonders hervor zu heben.

Gerade wenn man weiß das man ein Modul komplett abgedeckt hat und sie mit einem Knopfdruck verifizieren kann, hilft das dabei das man schnell mal ein paar Sachen fixt oder abändert, man kann dann jederzeit einfach nochmal den Knopf drücken und schauen ob man etwas kaputt gemacht hat.

Auch im Buch von Fowler (http://www.amazon.de/Refactoring-Studentenausgabe-vorhandener-verbessern-Programmers/dp/3827322782/ref=sr_1_9?ie=UTF8&s=books&qid=1280592376&sr=8-9) sieht man das, wenn man Units hat, viel effektiver bestehenden Code verbessern kann.

Bei meinem Tool auf arbeit zb folge ich der regel das ich nach jedem Refactoring Schritt ein weiterhin funktionierendes Modul habe.

Ich entwickel nicht nach dem TDD; Wollte mir mal noch ein Buch darüber besorgen. Aber ich schreibe schon Unit Tests (aber noch nicht so lange).

Hatte erst gestern wieder den klassischen Fall.
Wir hatten ein Bug entdeckt, ich habe ihn mit einem UnitTest reproduzieren können.
Beim Fixen habe ich dann immer wieder alle Units dieses Moduls laufen lassen, und es war erst gefixt wenn alle units wieder gepasst haben.
Bug gefunden -> Reproduziert mit einer Unit -> Gefixt -> Verifiziert mit den Units.
private Nachricht | Beiträge des Benutzers
delta†
myCSharp.de - Member



Dabei seit:
Beiträge: 46

beantworten | zitieren | melden

Was auch interessant ist, ist dass die Faustregel existiert das man dort wo ein Fehler gefunden wurde i.d.R. weitere finden wird. Hat jemand von euch eigentlich schon einmal einen maskierenden/maskierten Fehler gehabt? Was für Tool verwendet Ihr eigentlich für den Integrationstest?

delta†
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von delta† am .
private Nachricht | Beiträge des Benutzers
m0rius
myCSharp.de - Member

Avatar #avatar-3125.png


Dabei seit:
Beiträge: 1043

beantworten | zitieren | melden

Hallo Golo Roden,

ich schließe mich zero_x an und würde mich über ein paar Details zu deinem Sinneswandel freuen. Ich selbst schreibe zwar auch Unit Tests, allerdings habe ich noch nie wirklich TDD angewandt ...

m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

@Herbivore
Also das ist leider kein Einzelfall sondern die traurige Regel, jedenfalls bei mir.
Vielleicht kann man sowas besser aufziehen. Aber ich bin für mich zu dem Ergebniss gekommen: Wenn man die Unit Test für seinen Code selbst schreibt bringt das nichts oder wenigstens nicht genug und die wenigsten IT-Firmen die ich bisher kennengelernt habe leisten sich eine dahingende Infrastruktur wo Test Schreiber und Coder seperat agieren.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von user8744 am .
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Sebastian.Lange,
Zitat
denn man die Unit Test für seinen Code selbst schreibt bringt das nichts oder wenigstens nicht genug
das ist erneut eine Frage der Qualifikation bzw. - weniger hochgestochen formuliert - der Übung oder auch nur des Willens. Natürlich gibt es die Gefahr, dass man für bestimmte eigene Fehler bind ist. Aber dass Unit-Tests deshalb grundsätzlich nichts bringen, stimmt nicht, denn es ein großer Unterschied, ob ich programmiere oder teste.

Wenn ich programmiere, liegt mein Fokus auf der Herstellung der Funktionalität, also dem was funktionieren soll (konstruktiv). Wenn ich teste, liegt mein Fokus auf dem Finden von Fehlern, also dem, was möglicherweise nicht funktionieren könnte (destruktiv).

Diese unterschiedliche Sichtweise macht aus mir natürlich keine andere Person. Etwas, was ich in der Spezifikation missverstanden hab, kann ich durch keinen Test finden. Aber alle anderen Abweichungen zwischen Spezifikation und tatsächlichem Verhalten der Unit kann ich finden.

Wenn man die Unit-Tests natürlich nur als notwendiges Übel ansieht, dann wird man nicht den Ehrgeiz entwickeln, Tests zu schreiben, die fehlschlagen, sondern man wird nur Tests schreiben, die bestanden werden, damit man möglichst schnell fertig ist. Das ist der springende Punkt. Man muss beim Programmieren den Willen haben, Fehler zu vermeiden, aber man muss beim Testen den Willen haben, Fehler zu provozieren. Man ist dann immer noch dieselbe Person, aber man spielt unterschiedliche Rollen. Und dadurch sieht man Dinge, die einem nicht auffallen, wenn man immer nur ein und dieselbe Perspektive einnimmt.

Aber selbst wenn man durch Unit-Tests während der initialen Entwicklung keine zusätzlichen Fehler finden würde, bliebe immer noch der Riesenvorteil, dass man bei der späteren Weiterentwicklung nichts kaputt machen, was durch einen Test abgedeckt ist, also insbesondere keine Fehler erneut einbauen kann, die früher schon einmal behoben wurden.

herbivore
private Nachricht | Beiträge des Benutzers
Golo Roden
myCSharp.de - Member

Avatar #avatar-2167.png


Dabei seit:
Beiträge: 4649
Herkunft: Riegel am Kaiserstuhl

beantworten | zitieren | melden

Im Endeffekt war es bei mir folgende Erkenntnis:

- Code muss so oder so getestet werden. Wenn ich keine Tests dafür schreibe, muss ich es per Hand machen oder der Kunde macht es über kurz oder lang (unfreiwillig).

- Zwar kann ich meinen Code beim Schreiben per Hand testen und dann relativ sicher sein, dass er läuft - insofern kann ich mir dabei den Aufwand für manuelle Tests sparen. Doch was, wenn ich mal was ändern muss? Dann muss ich diesen Code erneut testen - und alles andere auch noch, weil es ja Seiteneffekte geben könnte ...

Die Konsequenz bislang war, dass ich ebendieses Testen nach Änderung weggelassen habe, weil es mir zu aufwändig und zu stupide war. Das Problem daran: Dadurch wird der Code auch nicht besser. Und wenn sich ein Fehler eingeschlichen hat, findet man ihn dadurch nicht - im Endeffekt liefert man also etwas aus, wovon man nicht mit Sicherheit weiß, ob es funktioniert.

Mit TDD kann das nicht mehr passieren: Da sämtlicher geschriebener Code per Test abgedeckt ist (bei TDD hat man ja, wenn man es richtig macht, immer eine Abdeckung von 100%), kann ich jederzeit automatisch prüfen lassen, ob alles noch so ist, wie ich mir das gedacht habe.

Klar kann es immer noch sein, dass ich irgendeinen Testfall vergessen habe - aber das kann mir im nicht-TDD-Betrieb auch passieren. Der Unterschied ist nur: Fällt mir bei TDD auf, dass ich einen Test vergessen habe, ergänze ich ihn, und bin auf der sicheren Seite, dass mir dieser Fehler nie wieder passieren kann.

Die Tage hatte ich so einen Fall: Ich hatte eine Klasse, prinzipiell ganz überschaubar, vielleicht 15 Methoden mit jeweils bis zu zehn Zeilen Code - also nichts großes. Die Klasse war aber relativ langsam, bis mir klar wurde, warum. Also habe ich den Code entsprechend geändert, um das Performanceproblem zu umgehen, und war damit zufrieden - tja, bis die Tests mir gesagt haben, dass ich vier Fehler drin habe, die ich vorher nicht hatte ... das wäre mir so erst viel später aufgefallen.

Dank TDD habe ich an dieser Stelle verhindern können, dass sich ein neuer Fehler unbemerkt einschleicht und ich habe nach wie vor das gute Gefühl, dass mein Code genau das macht, was er soll.

Daher: Nie mehr ohne :-)
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

Das man alles mit Units abdeckt ist die Definition von TDD? Ich dacht bei TDD geht es auch um die Reihenfolge, also erst Tests und dann ausbauen der Methoden?
Was du beschreibst ist doch Standard Unittesting. Mach ich auch so, ohne das ich sage das ich nach TDD entwickel.
Muss mir endlich mal ein Buch darüber holen ^^
private Nachricht | Beiträge des Benutzers
Golo Roden
myCSharp.de - Member

Avatar #avatar-2167.png


Dabei seit:
Beiträge: 4649
Herkunft: Riegel am Kaiserstuhl

beantworten | zitieren | melden

Zitat von CSL
Das man alles mit Units abdeckt ist die Definition von TDD?

Da haben wir uns missverstanden.

Ich sagte: Du hast bei TDD automatisch eine Abdeckung von 100%. Das liegt daran, dass Du zuerst den Test schreibst, und dann nur gerade so viel Code, um den Test zu erfüllen.

Natürlich ist TDD nicht definiert als "Sie machen TDD, wenn Sie 100% Codeabdeckung haben" - das geht auch ohne TDD ;-).
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

Also ich möchte dazu noch sagen, wir haben nur einen Server Entwickler
der auch seine Tests selbst schreibt. Ich meine mir ist aufgefallen das
es mit den Tests weniger gut läuft seitdem er wo immer es geht Linq verwendet.
Kann aber auch ein falscher Eindruck sein.
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

Was hat den Linq mit den UnitTests zu tun?
Man testet die Methoden, ob intern manuell eine Liste iteriert wird oder es mittels Linq geschieht macht doch gar kein unterschied.

Eventuell ist er einfach noch dabei Linq zu lernen, zu beginn passieren nun mal mehr Fehler.
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

@Golo Roden
Mir tut sich gerade eine frage auf.

Du sagst
Zitat
Das liegt daran, dass Du zuerst den Test schreibst, und dann nur gerade so viel Code, um den Test zu erfüllen

spricht das nicht etwas gegen die dynamic des Codes?
Hin und wieder ist es doch so, das wenn man eine klasse und deren Methoden das erste mal erstellt, sich später herausstellt das die Methoden etwas anders doch praktischer wären.
Wenn man dann Refactored, müsste man auch alle Unit neu beginnen -.-

Ich persönlich mach das immer so das ich die Units erst schreibe wenn die Klasse fertig ist, dann check ich per Units das die Klasse tut was sie soll bevor ich mich neuen aufgaben zu wende.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo CSL,

natürlich kann man erst den Code und dann die Test schreiben. Nur wäre das dann nicht mehr testdriven. Golo hat ja nur begründet, warum es bei TDD eine 100%ig Testabdeckung gibt. Er hat nicht gesagt, dass man TDD zwingend verwenden muss.

herbivore
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

Selbstverständlich.
Nur er schrieb ja "Nie mehr ohne", also müsste er ja eine gute Lösung des Problems haben. Diese würde mich interessieren.
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7547
Herkunft: Waidring

beantworten | zitieren | melden

Hallo,

ich schreib mittlerweile die Tests vorher denn mir ist es schon ein paar mal passiert dass ich bei nachherigem Schreiben des Tests durch "Betriebsblindheit" für die Klasse die ein oder andere Anforderung vergesse. Das kann mir so nicht mehr passieren.

Also nachdem die Schnittstelle definiert ist gibts den Test der als "erweiterte Spezifikation" dient. Damit meine ich dass im Interface nichts von Wertebereichen, etc. zu finden sind. Im Test lassen sich diese einfach "angeben".


mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
private Nachricht | Beiträge des Benutzers
Golo Roden
myCSharp.de - Member

Avatar #avatar-2167.png


Dabei seit:
Beiträge: 4649
Herkunft: Riegel am Kaiserstuhl

beantworten | zitieren | melden

Zitat von CSL
Du sagst
Zitat
Das liegt daran, dass Du zuerst den Test schreibst, und dann nur gerade so viel Code, um den Test zu erfüllen

spricht das nicht etwas gegen die dynamic des Codes?
Hin und wieder ist es doch so, das wenn man eine klasse und deren Methoden das erste mal erstellt, sich später herausstellt das die Methoden etwas anders doch praktischer wären.
Wenn man dann Refactored, müsste man auch alle Unit neu beginnen -.-

Die Tests decken die Semantik ab. Refactoring betrifft per Definition ja aber nicht die Semantik, sondern nur die Struktur. Die Tests bleiben davon also erst mal unberührt.

Ich sag mal so: Für den Test, der eine Add-Methode testen soll, ist es ja schnuppe, ob die Add-Methode intern einfach stur runtergeschrieben ist, oder eine SOA-Implementierung eines generischen Rechenservices nutzt, mit verteilten Prozessen und und und ... insofern kannst Du im Hintergrund so viel refaktorisieren wie Du willst, so lange der Test grün bleibt.

Etwas anderes ist es, wenn die architektonische Veränderung auch die API verändert - dann heißt es natürlich, Tests anpassen. Das ist umständlich, aufwändig, macht keinen Spaß, aber man kommt halt nicht drumherum.

Das einzige, was dagegen hilft: Spikes / Prototypen und kleine Komponenten.

Spikes / Prototypen - weil man dann schon mal ein Gefühl dafür entwickelt, wie das ganze nachher aussieht.

Kleine Komponenten - weil man dann nicht all zu viel ändern muss.

Was ich hierbei übrigens auch sehr empfehlenswert finde, ist die Vorgehensweise, bei der Planung einer Komponente erst mal zu überlegen, wie ein Verwender diese einsetzen würde. Dadurch erspart man sich nachher viel Umbauarbeiten.
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de
private Nachricht | Beiträge des Benutzers
Golo Roden
myCSharp.de - Member

Avatar #avatar-2167.png


Dabei seit:
Beiträge: 4649
Herkunft: Riegel am Kaiserstuhl

beantworten | zitieren | melden

PS: Mal noch als (aktuelles) Beispiel. Gestern Abend musste ich ein doch etwas größeres Refactoring durchführen.

Das entsprechende Projekt besteht derzeit aus 1 Solution und 31 Projekten, wobei von dem Refactoring gut die Hälfte der Projekte betroffen war.

Kurzum: Das Refactoring hat mich rund 90 Minuten gekostet - 90 Minuten, bis sich alles wieder fehlerfrei übersetzen ließ. Tja, und dann? Früher hätte ich an dieser Stelle aufgehört, oder mich noch mal durch die Anwendung durchgeklickt, um zu sehen, ob noch alles geht (wie oberflächlich ein solcher "Ich klick mich mal durch"-Test ist, dürfte auf der Hand liegen).

Tja, und gestern? Tests wieder ausgeführt - und 9 der Tests waren rot. Ich wusste also nach nicht mal 2 Minuten, dass ich an 9 Stellen noch Probleme habe. Es hat mich dann ungefähr weitere 10 Minuten gekostet, die Fehler ausfindig zu machen und zu beheben, so dass alle Tests wieder grün waren.

10 Minuten, nach denen ich garantiert bekomme, dass alles, was vor meinem Refactoring getestet war und funktioniert hat, auch nach meinem Refactoring noch getestet ist und funktioniert.

Und nun die Gretchenfrage: Das Refactoring hätte mich mit oder ohne Tests 90 Minuten gekostet - hätte mich die Fehlersuche und -behebung ohne Tests auch nur 10 Minuten gekostet?

Wohl kaum ;-). Eher dramatisch länger - wenn *MIR* die Fehler überhaupt jemals untergekommen wären. Vielleicht hätte sie auch Monate später mein Kunde gefunden, und ich hätte suchen dürfen und hoffen und beten und schwitzen ...

Am Anfang wurde nach harten Zahlen gefragt - ich denke, dieses Beispiel spricht für sich.

Ach ja, und der Aufwand, die Tests zu schreiben: Klar ist der größer als 0. Aber der geht in dem Aufwand, den man betreibt, sich zu überlegen, wie die API aussehen sollte, unter. Ob ich die Überlegungen dann noch per Test ergänze oder nicht, macht zeitlich (und damit finanziell) kaum einen Unterschied.
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de
private Nachricht | Beiträge des Benutzers
Golo Roden
myCSharp.de - Member

Avatar #avatar-2167.png


Dabei seit:
Beiträge: 4649
Herkunft: Riegel am Kaiserstuhl

beantworten | zitieren | melden

So, ich habe noch darüber gebloggt: http://www.des-eisbaeren-blog.de/post.aspx?id=1cb31202-72a0-48bc-b433-4488c8b5c873
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

Das refactorings innerhalb der Methoden für die Units ungefährlich sind ist schon klar.

Meine refactorings sind hin und wieder aber auch so das ich zb eine Methode in zwei kleinere aufteile, zb da die Methode mehr gemacht hat als sie sollte (Single Responsibility Principle).
Solche Sachen kann ich schlecht vorher sehen, oft merk ich das schon direkt beim entwickeln, dh ich müsste dann ein paar Units anpassen noch bevor ich am Code weiter mach.

Oder, ich plane eine Klasse und habe dort eine Methode KocheKaffee vorgesehen, dann kann ich nun die Units schreiben, aber ich weiß doch noch gar nicht welche Methoden KocheKaffee alles benötigt, klar kann ich schon eine "HoleKaffeeFilter" Methode mit einplanen, nur dann weiß ich auch noch nicht ob ich dort intern eine "ÜberprüfeQualität" benötige.
Solche Kleinigkeiten sind nicht in der Planung enthalten, aber die möchte ich ja erst noch abdecken.

Oder ich merke beim entwickeln das die Methode "HoleKaffeeFilter" überflüssig ist, da es eine Filterlose Maschine ist, dann Lösch ich die einfach.

Alles Aktionen die Anpassungen in den Units erfordern, da ist es doch praktischer wenn der Code dahin gehend bereits "fertig" ist. Vor allem bei kleineren Umstellungen während der Entwicklung.

Ich mach es wie gesagt so das ich die Units erst schreibe wenn die Klasse fertig ist, und dann versuche ich jede Methode komplett aus zu reizen, dh Blödsinn übergeben etc.

Ich versuche immer das alle Methoden einer klasse mit Units getestet werden (auch die Privaten etc), wenn ich nach TDD entwickel müsste ich beim dritten refactoring schritt ja ständig die Units anpassen-

//Dazu
Deine Rechnung mit den 90min kann ich schon nachvollziehen, und auch verstehen, aber das bezieht sich ja eher auf UnitTests überhaupt als auf die Entwicklung nach TDD.
Bei deinem Beispiel hast ja schon den Fertigen Code, ob du die Units durch TDD erstelltest oder nachträglich ist da doch irrelevant.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von userid14268 am .
private Nachricht | Beiträge des Benutzers
SeboStone
myCSharp.de - Member



Dabei seit:
Beiträge: 495

beantworten | zitieren | melden

Zitat von CSL
Oder, ich plane eine Klasse und habe dort eine Methode KocheKaffee vorgesehen, dann kann ich nun die Units schreiben, aber ich weiß doch noch gar nicht welche Methoden KocheKaffee alles benötigt

Ich denke, dann hast Du Deine Klasse nicht wirklich ausreichend geplant, oder die Anforderungen für Deine Funktionen wurden zu schwammig definiert.
Zitat von CSL
nur dann weiß ich auch noch nicht ob ich dort intern eine "ÜberprüfeQualität" benötige.

Wo ist das Problem? Wenn Du merkst Dir fehlt noch etwas, dann schreibst Du einfach die Tests für die neue Methode und dort wo sie aufgerufen werde soll expectest Du dann den Methoden-Call z.B. mit Rhino.Mocks - das sind höchstens 2 Zeilen mehr in einem bestehenden Test, vorausgesetzt Du entwickelst tatsächlich nach CCD, Deine Signatur lässt das vermuten.

Und Klassen-/ Komponentenintegrationstests lassen sich alle Mal TDD entwickeln.
private Nachricht | Beiträge des Benutzers
Golo Roden
myCSharp.de - Member

Avatar #avatar-2167.png


Dabei seit:
Beiträge: 4649
Herkunft: Riegel am Kaiserstuhl

beantworten | zitieren | melden

"Nicht genug geplant" wäre jetzt auch meine Antwort gewesen.

Ein "Fehler" ist in meinen Augen auch, privates zu testen - es ist für den Unittest total egal, wie Du das intern aufziehst: Alles in einer Methode direkt, oder mit fünf privaten Methoden. Getestet wird nur die öffentliche Schnittstelle.

Denn nur die ist es, die den Verwender interessiert. Die Implementierung ist eine Blackbox.

Und was das Refactoring angeht, wenn eine Methode "zu viel" macht: Auch hier entweder wieder zu wenig geplant, oder - wenn Du nach TDD vorgehst - merkst Du ja schon beim Test schreiben, dass es sich irgendwie seltsam anfühlt, und kannst direkt gegensteuern.
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de
private Nachricht | Beiträge des Benutzers
SeboStone
myCSharp.de - Member



Dabei seit:
Beiträge: 495

beantworten | zitieren | melden

Zitat von CSL
Oder ich merke beim entwickeln das die Methode "HoleKaffeeFilter" überflüssig ist, da es eine Filterlose Maschine ist, dann Lösch ich die einfach.

Alles Aktionen die Anpassungen in den Units erfordern, da ist es doch praktischer wenn der Code dahin gehend bereits "fertig" ist. Vor allem bei kleineren Umstellungen während der Entwicklung.

Man könnte sagen, das klingt logisch, aber was machst Du wenn Du nach zwei Wochen weitere Features hinzufügen musst oder sie etwas ändern musst? Wann ist denn dann der Beste Zeitpunkt fürs Testen?

Nach Deiner Logik nach wäre es das Beste so lange mit den Tests zu warten bis die Klasse keinerlei Änderung mehr erfahren soll. Also eigentlich nie.
private Nachricht | Beiträge des Benutzers
SeboStone
myCSharp.de - Member



Dabei seit:
Beiträge: 495

beantworten | zitieren | melden

Zitat von Golo Roden
Ein "Fehler" ist in meinen Augen auch, privates zu testen - es ist für den Unittest total egal, wie Du das intern aufziehst: Alles in einer Methode direkt, oder mit fünf privaten Methoden. Getestet wird nur die öffentliche Schnittstelle.

Ah, das ist kein echter Unit Test mehr, das ist bereits eine Art Integrationstest. Ich denke beim Testen scheiden sich allgemein ein wenig die Geister. Jeder hat eine andere Teststrategie. Ich habe schon verschiedene Strategien ausprobiert, aber das Optimum habe ich für mich auch noch nicht herausgefunden. Zur Zeit teste ich hybrid. Das heißt ich habe Unit Tests die mir die die Methodenfunktionalität abdecken und Integrationstests welche mir die Funktionalität abdeckt.
Zitat von Golo Roden
Auch hier entweder wieder zu wenig geplant, oder - wenn Du nach TDD vorgehst - merkst Du ja schon beim Test schreiben, dass es sich irgendwie seltsam anfühlt, und kannst direkt gegensteuern.

Absolut!

//edit: kleiner Fehler in der Wortwahl gefixt
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von SeboStone am .
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

Hmm, ok das mit der Planung klingt einleuchtend.
Ich finde es des weiteren aber auch besser wenn man die Methoden innerhalb der Klasse auch einzeln testet, so kann man viel einfacher alle möglichen cases abdecken.

Ich habe zb die private Methode die ermittelt die Qualität des Kafeefilters, dann schreib ich ein Unit zu dieser Methode und kann die mit allen möglichen Parametern voll spamen.

Ein Test für den Gesamtablauf ist sowieso dabei, nur durch dieses detailierte Testen kann ich dann schneller Fehler finden, wenn die Klasse mit der Methode "KocheKaffee" fehlt schlägt, kann ich vorher schon sagen das es daran liegt das die Filterqualität falsch berechnet wird.

Also ich teste im Prinzip alles was in der Klasse da ist.

@SeboStone
Mit Mocks habe ich derzeit (leider) noch nichts gemacht, bin noch sehr bei den Anfängen von CCD, sehe mich noch beim Roten Grad (Überprüfe es hiermit: http://github.com/DavidWCSL/CC-Watcher).
Zitat
Man könnte sagen, das klingt logisch, aber was machst Du wenn Du nach zwei Wochen weitere Features hinzufügen musst oder sie etwas ändern musst? Wann ist denn dann der Beste Zeitpunkt fürs Testen?

Nach Deiner Logik nach wäre es das Beste so lange mit den Tests zu warten bis die Klasse keinerlei Änderung mehr erfahren soll. Also eigentlich nie.
Mein Zeitpunkt wann ich die Units erstelle ist immer nach Fertigstellung der Klasse, dh wenn keine weiteren Änderungen geplant sind. Auch wenn neue Features kommen werden diese implementiert, dann die Units aufgefrischt. Nebenbei können die bereits vorhandenen Units verifizieren das ich beim erweitern nichts zerstöre.
Laufe bisher recht gut damit.

Zu TDD selber sagte ich ja schon mehrfach das ich mir demnächst endlich mal ein Buch besorgen muss, damit ich da auch sicherer bin, habe bestimmt nur hier und da kleine Denkfehler.
private Nachricht | Beiträge des Benutzers
Golo Roden
myCSharp.de - Member

Avatar #avatar-2167.png


Dabei seit:
Beiträge: 4649
Herkunft: Riegel am Kaiserstuhl

beantworten | zitieren | melden

Die Frage ist doch, ob das Überprüfen der Qualität überhaupt in die Klasse gehört, die den Kaffee kocht - oder ob das nicht als public-Methode in eine eigene Kaffee-Qualitäts-Tester-Klasse gehört.

Aus meiner Erfahrung deutet der Bedarf, privates zu testen, meistens darauf hin, dass Komponenten noch nicht fein granular genug sind.

A propos Buch:

Als Empfehlung: Review von Pragmatic Unit Testing
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de
private Nachricht | Beiträge des Benutzers
SeboStone
myCSharp.de - Member



Dabei seit:
Beiträge: 495

beantworten | zitieren | melden

Mmh, Du hast in Deinen Klassen sicherlich Methode welche andere Methoden derselben Klasse aufrufen. Und dann hast Du sicherlich Methoden welche Methoden von Dependencies aufrufen. Wie testest Du so was? So was testen kannst Du ohne Mocks gar nicht, Du könntest so was nur testen, wenn dadurch states manipuliert würden und Du diese prüfst. Du kannst natürlich Mocks auch selber schreiben anstatt sie z.B. mit Rhino.Mocks zu generieren, aber das ist erstens erheblich aufwendiger und zweitens extrem fehlerträchtig.
Zitat von CSL
Mit Mocks habe ich derzeit (leider) noch nichts gemacht

Ok, das erklärt das eine oder andere Statement. Wenn Du Dich damit mal befasst hast, dann wird sich Deine Meinung bezüglich TDD sicherlich etwas ändern. Du wirst es dann auch mit dem Testen leichter haben. Ich kann mir gut vorstellen, dass Du bereits auf Code gestoßen bist wo Du nicht weißt wie Du das testen sollst.
Zitat von CSL
Zu TDD selber sagte ich ja schon mehrfach das ich mir demnächst endlich mal ein Buch besorgen muss, damit ich da auch sicherer bin, habe bestimmt nur hier und da kleine Denkfehler.

Naja, ein Buch schafft man sich an wenn man eine neue Technologie nutzen möchte. TDD ist nur eine Herangehensweise, ein Prozess, der ist schnell erklärt, da brauchts kein Buch, aber sehr viel Zeit und Ausdauer das ganze zu probieren und dabei zu bleiben. Am Anfang ist das nicht einfach und die Entwicklung verläuft sehr schleppend, aber es lohnt sich.


PS: Die CCD Grade sind nicht dafür gedacht dass Du sie stur Top Down in Dich reinklopfst. Es ist völlig legitim, dass Du auch mal in die anderen Grade hineinschnupperst und Dir das raus ziehst was Du sofort brauchen kannst. Continous Integration ist so ein Thema, dass Du - wenn Du es noch nicht hast - als nächstes einsetzen solltest.
private Nachricht | Beiträge des Benutzers
SeboStone
myCSharp.de - Member



Dabei seit:
Beiträge: 495

beantworten | zitieren | melden

Zitat von Golo Roden
Die Frage ist doch, ob das Überprüfen der Qualität überhaupt in die Klasse gehört, die den Kaffee kocht - oder ob das nicht als public-Methode in eine eigene Kaffee-Qualitäts-Tester-Klasse gehört.

Sicherlich würde es eine Klasse "KaffeeKochen" und eine Klasse "Kaffee" geben welche dann auch Aussagen über die Qualität treffen kann. Aber ich denke das ist an dieser Stelle erstmal gar nicht relevant.
Zitat von Golo Roden
Aus meiner Erfahrung deutet der Bedarf, privates zu testen, meistens darauf hin, dass Komponenten noch nicht fein granular genug sind.

Mmh, an der Stelle meinst Du sicherlich "Klassen" und nicht "Komponenten". denn wenn dem so wäre, dann müssten Deine Solutions hunderte Projekte beinhalten.

Ich bin der Meinung, dass es tatsächlich Sinn macht "privates" ebenfalls zu testen. So sehr lassen sich Klassen nicht granulieren ohne insgesamt eine Absurdität zu werden. Man ist gar nicht in der Lage alle möglichen Fehlerquellen schon gar nicht Fehlermöglichkeiten alleine durch Tests auf den Interface Methoden und Properties abzudecken. Aber tatsächlich würde ich nicht auf privaten Methoden rum rutschen, ich weißt mit dem MS TestFramework geht das aber mit internals und InternalsVisibleTo hat man doch recht gute Möglichkeiten. Sobald man mit Rhino.Mocks anfängt wird man je nach Ausprägung und Teststrategie sowieso an den Zugriffmodifizierern noch einige Kompromisse eingehen müssen.

Aber wie gesagt, es gibt unterschiedlichen Teststrategien, jede hat seine Vor- und Nachtteile und keine ist meiner Erfahrung nach für sich alleine gesehen ausreichend. Meiner Erfahrung nach ist eine Mischung aus Unit-Tests (wie es CSL propagiert) und (Komponenten-) Integrationstests (wie es Golo Roden propagiert) die beste Möglichkeit der Qualität einer Software auf die Sprünge zu helfen.
private Nachricht | Beiträge des Benutzers
userid14268
myCSharp.de - Member



Dabei seit:
Beiträge: 1620

beantworten | zitieren | melden

Zitat von SeboStone
PS: Die CCD Grade sind nicht dafür gedacht dass Du sie stur Top Down in Dich reinklopfst. Es ist völlig legitim, dass Du auch mal in die anderen Grade hineinschnupperst und Dir das raus ziehst was Du sofort brauchen kannst. Continous Integration ist so ein Thema, dass Du - wenn Du es noch nicht hast - als nächstes einsetzen solltest.
Das mache ich auch Ich sehe die Grade aber als eine gute Möglichkeit CCD gut zu erlernen und sich selbst zu überprüfen, ich sehe mich auf den Roten Grad weil das das einzigste ist wo ich tatsächlich alle Prinzipien einhalte, ich beachte natürlich auch noch andere Prinzipien, zb YAGNI kommt ja sehr spät.

Ich mache derzeit tatsächlich nur UnitTesting, zu Integration Tests wollte ich mich auch noch schlau machen.


PS. Ich habe gut schwafeln, soo lange mach ich UnitTest im allgemeinen noch nicht
private Nachricht | Beiträge des Benutzers
spike24
myCSharp.de - Member



Dabei seit:
Beiträge: 451
Herkunft: Steiermark Österreich

beantworten | zitieren | melden

In meiner "langen" Zeit als Programmierer wo ich auch Test schreiben "muss" hat es bis jetzt nur einen Fall gegeben in der es angebracht war eine private Methode zu testen.
diese eine Methode wurde von 2 public aufgerufen und hat selbst ein mehr oder weniger kompliziertes XML überprüft und an gut 15 Stellen Exceptions geworfen
Ergo wenn ich nur die public Methoden getestet hätte, hätte ich original die Testmethoden kopiert und alles wäre 2 mal dagestanden.

Bei meinem privaten Projekt gehe ich "momentan" einen anderen Weg:
Ich teste nur Klassen die ein public Interface implementieren.
und das nicht als Unittest, sondern als Integrationstest mit Abhängigkeiten

Beispiel:
eine Klasse implementiert IConnector und hat 2 Methoden
hier teste ich mit allen möglichen richtigen Aufrufen und speichere das Ergebniss in einem XML File. (die Aufrufe die Exception produzieren müssen noch nachgeliefert werden, habe im Schnitt alle 30 Zeilen ein TODO stehen :-) )
eine Klasse implementiert IObjectStoreService welche im ctor einen IConnector bekommt.
Diesen IConnector Mocke ich (NMock2) und bei den Expections lade ich als Rückgabewert die XML-Files der IConnector-Tests.
Somit teste ich die IObjectStoreService-Klasse mit realen Werten ohne eine "direkte" Abhängigkeit zu haben.

Ich habe eingangs geschrieben "momentan", mir ist bewusst dass sich meine Teststrategie ändern wird (z.b. mehr Richtung Unittesting) aber mit diesem System habe ich alle bekannten Probleme beim Testschreiben erschlagen.

Zurück zum Thema:
private Methoden zu testen macht insofern wenig Sinn wenn diese private Methode bei der KaffeeQualität was auszusetzen hat wirft sie eine Exception. Gut, und was macht die Methode die die private Methode aufruft mit dieser Exception?
d.h. Du musst für die public den gleichen TestCase nochmal schreiben nur um sicherzustellen das die Methode die Exception nicht fängt sondern weiterrasseln lässt.
Noch umständlicher wird es bei 2 public Methoden
z.b. value GetValue(key) und bool TryGetValue(key, out value)
da brauchst Du für KeyNotFoundException 3 tests.

wie gesagt in den letzten 3 Jahren habe ich eine private Methode getestet und da haben wir gute 30 Minuten darüber diskutiert ob das wirklich sein muss.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von spike24 am .
mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10076

beantworten | zitieren | melden

Naja, aber wenn eine einzelne Routine 15 Punkte hat an der sie Exceptions werfen kann, ist diese Routine definitiv falsch erstellt.

Man könnte die dann wie Golo oben aufführte feiner granulieren und wahrscheinlich eine eigene Klasse draus machen, mit einem public Interface.

Und schon kannst Du sie vernünftig testen.

TDD ist nicht nur Selbstzweck, sondern soll einem auch die Augen öffnen für unnötige Kopplung und vernünftige Granulierung, bzw vernünftiges Design.
private Nachricht | Beiträge des Benutzers