Laden...

Tatsächlicher Nutzen von Unit-Tests [und TDD]

Erstellt von Rainbird vor 13 Jahren Letzter Beitrag vor 13 Jahren 53.354 Views
6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

den Fehler im Assert von gfoidl

Mein Assert ist schon richtig denn das wird nur für einen Test für positive Eingaben verwendet. Und da sollte bei der Addition eben ein positives Ergebnis herauskommen.

ad PEX: Siehe Unit-Tests mit PEX

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!"

U
208 Beiträge seit 2008
vor 13 Jahren

Ich hab keine Ahnung, ob ich damit jetzt alle Eventualitäten drin habe. Aber genau darin liegt das problem. wenn ich mir alle Eventualitäten überlege, fange ich diese Sachen bereits bei der Realisierung ab.

Niemand denkt immer an alle Eventualitäten. Und gerade deshalb sollte man doch auch Tests schreiben. Bei der Erstimplementation einer Funktionseinheit wirst du nur so viele Fälle abdecken, die dir einfallen, geht ja nicht anders. Wenn dann aber die Software irgendwann in Betrieb ist und bei irgendeinem Anwender tritt aufgrund ungewöhnlicher Eingaben oder Eingaben, an die du nicht gedacht hast, ein Fehler auf, dann kannst du speziell diesen Fall mit einem Test abdecken und stellst sicher, dass der Fehler ein für alle mal behoben ist. Nicht, dass bei einer weiteren Änderung am Code der Fehler noch mal versehentlich eingebaut wird.

656 Beiträge seit 2008
vor 13 Jahren

Problem bei Pex ist oft, dass es bei etwas "komplexeren" Sachen oft schon ansteht und nicht mehr weiterkann (was mir oft passiert ist, bis ichs irgendwann mal sein gelassen hab: Parameter-Objekte, die mehrere andere Parameter zusammenfassen und im Vorfeld schon validieren). Und dort per Code und den von Pex benötigten Object Factories nachhelfen funktioniert(e) damals auch nicht ganz reibungslos.
Umgekehrt konnte ich aber mit CrashTest.net teilweise bessere Ergebnisse erzielen als mit Pex (hat manchmal die Parameter-Objekte richtig gemacht), war dafür ab und zu nicht ganz so stabil (bleibt hängen, reagiert nicht mehr oder stürzt auch mal mit einer unhandled Exception ab).

Um zu den Tests als Dokumentation, TDD und Co zurück zu kommen:
Was ich schon mehrmals gemacht habe, war die Anforderungsdokumente von Kunden und/oder Vorgesetzten als Test zu formulieren - damit ist mal sichergestellt, dass das funktioniert, was gefordert ist. Natürlich TDD-Style, erst den Test, dann implementieren. Im Anschluss kurz die Code-Coverage anschaun, ob irgendwas nicht durch den Test erwischt wurde; dafür schreib ich dann ggf. auch was (Alles natürlich unter der Vorraussetzung, dass die Anforderungsdokument auch einigermaßen das enthalten, was man braucht - und nicht was man denkt dass man braucht. Aber das Problem gibts überall und muss man irgendwo selber abschätzen können).

Für Fälle, die ich nicht kenne, schreibe ich logischerweise auch keinen Test. Vor allem: sollte so ein Spezialfall fehlschlagen, muss ich mit ziemlicher Sicherheit sowiso den Code anpassen und ggf. auch weitere Tests schreiben. Da halte ich es wie mit den Exceptions, don't catch what you don't expect.

Einen Punkt habe ich oben bewusst nicht erwähnt, den ich aber teilweise bei meinen Kollegen sehe oder zumindest schon mehrmals als Diskussionspunkt hatte:
Testet ihr (erfolgreiche) Fälle von Konstruktoren und Properties? Beispiel: Ctor setzt das Property "Name" auf den übergebenen Wert, Test mit

Assert.Equals(expected, new MyObject(expected).Name);

Oder es gibt eine automatische Property Name; testet ihr dort ob das Framework das richtige tut; zur Sicherstellung dass es sich auch in Zukunft so verhält (und nicht dass mal eine Validierung im set reinkommt, die alles kaputt macht):

class UnderTest { public string Name { get; set; } }
[...]
Assert.DoesNotThrow(() => underTestInstance.Name = expected);
Assert.AreEqual(expected, underTestInstance.Name);
S
1 Beiträge seit 2010
vor 13 Jahren

@Rainbird

Ich habe diesen Thread noch nicht bis zum Ende gelesen aber bis jetzt wurde dieses Buch noch nicht erwähnt: "Springer 2010 Test-Driven Development An Empirical Evaluation of Agile Practice" Amazon

Ich habe das Buch noch nicht gelesen da ich auch so von TDD und Unit-Tests überzeugt bin, allerdings beantwortet es vielleicht Deine Fragen.

LG.

M
164 Beiträge seit 2009
vor 13 Jahren

Ich glaube, das folgende Argument (pro) TDD ist bislang noch nicht erwähnt worden:

  • Man kann sicherstellen, dass der Code so verwendet wird, wie es zur Designzeit gewünscht ist.

... dann schreibe ich einen Test dafür und wenn jemand meinen Code ändert, failed ein Test. Dann muss er zumindest diesen auch noch anpassen und überlegt sich vielleicht, ob seine Änderung überhaupt sinnvoll ist, wenn dafür speziell ein Test existiert, der dies verhindert...

(ich hoffe, ich hab mich genug deutlich ausgedrückt 😉 )

160 Beiträge seit 2008
vor 13 Jahren

Da ich mich mit genau dem Thema gerade beschäftige
ist die Sache für mich sehr interessant, denn:

a) sind automatisierte Tests eine tolle Sache - vor allem wenn einer an meinem Code fummelt und dann Funktionen nicht mehr funktionieren.

b) es für Kunden natürlich nichts blöderes und ärgerlicheres gibt , als einmal funktionierende Sachen wieder zu bemängeln

c) die Wartung im Nachhinein wesentlich vereinfacht werden kann

aber:

Projekte sind oft zeitkritisch. Und wenn der Chef oder der Kunde morgen neue Funktionen haben will und ich ihm mitteile für die eigentliche Aufgabe gerade bis morgen fertig werde aber zusätzlich noch Testfunktionen implementieren muss,
dann klatscht der Ledernacken.

Für die Chefetage und somit meist Nichtprogrammierer ist das ganze oft ein unverständlicher zeit und kostenintensiver Faktor, der auf Inakzeptanz stößt
(meist zumindest). Berühmte Worte meines Ex-Chefs waren immer: Das haben wir doch schon alles mal programmiert - wieso dauert das solange....

...und da liegt die Sache im Argen. Wer gibt einem die Zeit dafür, für jede Klasse, Funktion und eventuell Variable eine zusätzliche Testfunktion zu schreiben.

In kleinen Projekten würde ich sogar darauf verzichten. Ich denke je größer und kostenintensiver das Projekt ist, desto mehr lohnt sich auch ein abgestellter Testentwickler oder Qualitätsmanager. Aber aufs Jahr gesehen kostet der auch fast 100.000 Euro mit Lohnnebenkosten. Wers hat...

Den Kunden zu verärgern und Fehler immer wieder neu aufzudecken kann aber genauso teuer werden.

„Wenn man eine Katze auseinandernehmen will, um zu sehen, wie sie funktioniert, hat man als erstes eine nicht funktionierende Katze in den Händen.“

D
42 Beiträge seit 2010
vor 13 Jahren

hier ist es zwar schon ein paar wochen ruhig!? ich finde es sinnvoll dass ein entwickler sich - auf dauer gesehen - testwissen aneigent um seine strukur der programmierung entsprechend weiterzuentwickeln!

meistens wird der komponententest bei den entwicklern durchgeführt, wobei es hier mehr sinn macht das buddy-testing angewendet wird - aus dem einfachen grund das der entwickler der komponente meist unter betriebsblindheit leidet oder das projekt oder die firma sehr klein ist und die ressourcen nicht für einen testabteilung reichen.

mal abgesehen davon sollte man jedoch auch wissen über die testfallbildung mitbringen wie z.b. äquivalenzklassenbildung, grenzwertanalyse, bedingungsübdeckung, etc. und sich mit gewissen metriken z.b. mccabe auseinandergesetzt haben. es gibt auch bücher mit fehlerlisten die unter umständen recht sinnvoll sein können.

oft wird testen mit dem finden von fehlern gleichgesetzt. grundsätzlich kann man mit dem testen die existent von fehlern nachweisen - jedoch nicht die abwesenheit. dies ist aber nur ein teil der absicht des testprozesses. der sinn ist auch das die sw-qualität (gebrauchsqualität sowie innere und äußere qualität) gesteigert wird und sich damit etliche kostenfaktoren senken lassen. man sollte natürlich auch beachten das es neben den dynamischen methoden wie blackbox und whitebox auch noch die statischen gibt welche oftmals ganz andere perspektiven und damit andere testfälle zum vorschein bringen.

delta†

Gelöschter Account
vor 13 Jahren

Ohne irgendwelche Antworten hier gelesen zu haben.

Server-Entwickler: Meine Unit Test funktionieren!

Ich: Ich rufs auf und bekomm ne Exception.

Meine Meinung von Unit Tests ist eine eher schlechte.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo Sebastian.Lange,

aufgrund eines Einzelfalls sollte man kein grundlegendes Urteil fällen.

Davon abgesehen ist aufgrund deiner sehr knappen Beschreibung überhaupt nicht klar ist, ob es überhaupt einen Widerspruch zwischen den beiden Aussagen gibt. int.Parse ist auch ausführlich getestet. Und trotzdem kommt bei int.Parse ("hallo") eine Exception. Das ist ja vollkommen korrekt.

Außerdem musst du zwischen Korrektheit und Robustheit unterscheiden. Korrektheit bedeutet nur, dass eine Methode, die korrekt ist, das tut, was die Spezifikation verlangt. Legt die Spezifikation die Aufgabe der Methode nur für einen Teilmenge der möglichen Eingaben fest, dann ist keine Aussage darüber getroffen, was die Methode tun soll, wenn ein Eingabewert außerhalb des durch die Spezifikation definierten Wertebereichs liegt. Wenn die Methode dann Unsinn macht, ist sie nicht robust, aber sie kann trotzdem korrekt sein, weil sich Korrektheit nur auf die gültigen Eingaben bezieht.

Aber selbst wenn die Methode, die du aufgerufen hast, nicht korrekt war und die Exception fälschlich geworfen hat, sag das doch immer noch nichts darüber aus, ob es sinnvoll ist, Unit-Tests einzusetzen. Tests können normalerweise nicht die Abwesenheit von Fehlern beweisen. Das Unit-Tests erstellt wurden, heißt also nicht, dass die Unit vollkommen fehlerfrei ist. Die Frage ist, ob die Unit weniger Fehler enthält, wenn Unit-Tests erstellt wurden. Und das kann man mit Fug und Recht als empirisch bewiesen ansehen.

Vermutlich macht deinen Beispiel einfach keine Aussage über den Sinn von Unit-Tests, sondern nur über die (mangelnde) Qualifikation dieses einen Entwicklers.

herbivore

4.207 Beiträge seit 2003
vor 13 Jahren

Hallo,

um mich auch mal noch einzuklinken: Ich war ja bis vor rund 9 Monaten auch einer derjenigen, die gesagt haben: Unittests - ja, ganz nett, aber viel zu umständlich, viel zu aufwändig, erfordert viel zu oft Umstrukturieren von Code, ... wer meine Argumentation von damals noch mal haben will, kann dies gerne in meinem Blogeintrag "Wie viel Sinn machen Unittests?" (http://www.des-eisbaeren-blog.de/post.aspx?id=c9a5d57d-7337-49f8-b950-c082d49b2fdb) machen.

Heute, 9 Monate später, sehe ich das Ganze komplett anders.

Auf meinen Blogeintrag kamen etliche Kommentare, die mich erschreckt haben - und glücklicherweise dazu veranlasst, es noch einmal zu versuchen. Ich habe mich danach ausführlich mit Unittests und TDD beschäftigt, viel gelesen - aber, was noch wichtiger ist: Viel herumprobiert und mit anderen diskutiert.

Das Ergebnis: Ich habe festgestellt, dass ich den wahren Nutzen von Unittests früher gar nicht erkannt habe. Früher dachte ich, es geht darum, Fehler zu finden.

Heute weiß ich: Es geht darum, ein Sicherheitsnetz zu haben, das es mir ermöglicht, bedenkenlos Änderungen am bestehenden Code durchzuführen - mit der Garantie, dass ich nichts aus Versehen kaputt mache oder die bestehende Semantik ändere.

Und auch TDD weiß ich heute sehr zu schätzen: Es fördert gutes Design, man macht sich viel mehr Gedanken über Terminologie, Struktur, ... und vor allem: Man schreibt nur so viel Code wie nötig, hält alles damit kompakt, refaktorisiert regelmäßig, ...

Natürlich kostet das ganze Aufwand. Dieser Aufwand fällt aber gar nicht so sehr während der Entwicklung ins Gewicht - sondern vielmehr während des "sich Eingewöhnens". Unittests und vor allem TDD fühlen sich zu Anfang ungewohnt an - und deswegen scheut man sie (zumindest ging mir das so). Inzwischen bin ich froh, diese Veränderung durchgemacht zu haben.

Ich entwickle derzeit ein neues Projekt, Greenfield, .NET 4.0 - komplett mit TDD. Es käme mir nicht mehr in den Sinn, es anders zu machen. Die Tests haben mir schon ein paar Mal geholfen, bei Refaktorisierungen auf der sicheren Seite zu bleiben. Ohne sie hätte ich schon einige Fehler eingebaut, von denen ich nichts ahnen würde ... und die dann irgendwann irgendwo auftreten - im dümmsten Fall nach der Auslieferung beim Kunden.

Insofern: TDD? Nie mehr ohne 😃!

Viele Grüße,

Golo

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

1.044 Beiträge seit 2008
vor 13 Jahren

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

U
1.578 Beiträge seit 2009
vor 13 Jahren

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.

D
42 Beiträge seit 2010
vor 13 Jahren

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†

1.002 Beiträge seit 2007
vor 13 Jahren

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

Gelöschter Account
vor 13 Jahren

@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.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo Sebastian.Lange,

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

4.207 Beiträge seit 2003
vor 13 Jahren

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

U
1.578 Beiträge seit 2009
vor 13 Jahren

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 ^^

4.207 Beiträge seit 2003
vor 13 Jahren

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

Gelöschter Account
vor 13 Jahren

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.

U
1.578 Beiträge seit 2009
vor 13 Jahren

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.

U
1.578 Beiträge seit 2009
vor 13 Jahren

@Golo Roden
Mir tut sich gerade eine frage auf.

Du sagst

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.

49.485 Beiträge seit 2005
vor 13 Jahren

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

U
1.578 Beiträge seit 2009
vor 13 Jahren

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.

6.911 Beiträge seit 2009
vor 13 Jahren

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!"

4.207 Beiträge seit 2003
vor 13 Jahren

Du sagst

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

4.207 Beiträge seit 2003
vor 13 Jahren

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

4.207 Beiträge seit 2003
vor 13 Jahren

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

U
1.578 Beiträge seit 2009
vor 13 Jahren

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.

S
489 Beiträge seit 2007
vor 13 Jahren

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.

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.

4.207 Beiträge seit 2003
vor 13 Jahren

"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

S
489 Beiträge seit 2007
vor 13 Jahren

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. 🙂

S
489 Beiträge seit 2007
vor 13 Jahren

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.

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

U
1.578 Beiträge seit 2009
vor 13 Jahren

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).

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.

4.207 Beiträge seit 2003
vor 13 Jahren

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

S
489 Beiträge seit 2007
vor 13 Jahren

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.

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. 😉

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.

S
489 Beiträge seit 2007
vor 13 Jahren

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.

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. 🙂

U
1.578 Beiträge seit 2009
vor 13 Jahren

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 😉

S
443 Beiträge seit 2008
vor 13 Jahren

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.

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

F
10.010 Beiträge seit 2004
vor 13 Jahren

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.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo FZelle,

wenn eine Methode verschiedene Aspekte einer XML-Datei überprüft, dann finde ich es vollkommen gerechtfertigt, wenn es da viele Stellen gibt, die eine Exception werfen. Dass es diese vielen Stellen gibt, ist kein Argument für eine Aufteilung.

Aber selbst wenn man die einzelnen Prüfungen in einzelne Methoden packen würden, bräuchte man sinnvollerweise eine Methode, die die ganzen Prüfungen hintereinander aufruft. Und diese Methode würde dann (indirekt) 15 Exceptions werfen können. Man hätte also nichts gewonnen.

Davon abgesehen geht dein Einwand an dem eigentlichen Punkt voll vorbei. Hier ging es ja darum, ob private Methoden getestet werden sollen oder müssen. spike24 hat argumentiert, dass man private Methoden normalerweise nicht testen muss. Sein Beispiel hat er als Ausnahme von dieser Regel angeführt. Und diese basiert darauf, dass die private Funktionalität an verschiedenen Stellen benutzt wurde. Das wäre aber auch nach einer Aufteilung in viele kleine (natürlich ebenfalls private) Methoden so. Eine etwaige Aufteilung ändert also überhaupt nichts an dem eigentlich zur Diskussion stehenden Punkt.

herbivore

S
443 Beiträge seit 2008
vor 13 Jahren

@FZelle
Es ist eh nicht eine einzelne Methode, weis es zwar nicht mehr genau, aber soweit ich mich errinnern kann gibt es für jeden NodeType in dem XML eine eigene Methode. oder so ähnlich. Eine Methode alleine hätte den Review eh nicht geschafft.

Kann es sein, dass es Dich gibt seit dem ich programmiere?

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

F
10.010 Beiträge seit 2004
vor 13 Jahren

Nein, ich bin schon älter 😉
aber wir kennen uns aus nem anderen Forum, sozusagen aus nem anderen Leben.

@herbivore:

Davon abgesehen geht dein Einwand an dem eigentlichen Punkt voll vorbei. Hier ging es ja darum, ob private Methoden getestet werden sollen oder müssen.

Dann habe ich mich etwas missverständlich ausgedrückt.
Ich persönlich halte nichts von Tests für internal oder private, denn private und internal bedeuten das es sich jederzeit ändern kann, denn es ist kein Bestandteil des Kontraktes dieser Klasse.

Aber wenn etwas so wichtig ist, das man meint es testen zu müssen, dann ist es automatisch falsch als privat oder internal deklariert.

Und das ist eben einer der Aspekte von TDD, man sieht beim Erstellen des Kontraktes ( denn der kommt zuerst ) was zu testen ist, und alles was zu testen ist ist eben öffentlich.

Und was nicht öffentlich ist, braucht auch nicht getestet werden.

Und zu Spikes beispiel, das sehe ich anders.
Wenn eine Routine so gross wird, hat man wahrscheinlich einiges beim Design nicht beachtet.
Gerade bei XmlParsern kann man durch vernünftige Pattern Ausnutzung sehr häufig den Code drastisch verkleinern.
Aber das kann man nur konkret machen, nicht pauschal oder abstrakt.

S
72 Beiträge seit 2009
vor 13 Jahren

(...)
Aber wenn etwas so wichtig ist, das man meint es testen zu müssen, dann ist es automatisch falsch als privat oder internal deklariert.

Und das ist eben einer der Aspekte von TDD, man sieht beim Erstellen des Kontraktes ( denn der kommt zuerst ) was zu testen ist, und alles was zu testen ist ist eben öffentlich.

Und was nicht öffentlich ist, braucht auch nicht getestet werden.
(...)

Hallo FZelle,

deine Aussage würde aber bedeuten, das Hilfsklassen einer Assembly, welche internal sind, nie getestet werden. Oder würdest du diese auch implizit durch die öffentlichen Kontrakte mittesten?

F
10.010 Beiträge seit 2004
vor 13 Jahren

Unittests sind u.a. dazu da agiles entwickeln zu erleichtern.

Bei den agilen Methoden geht es u.a. darum, nur das zu implementieren, was der Kunde gerade wirklich braucht/bestellt hat und wenn sich die Vorgaben und Ziele ändern den Code "gefahrlos" refaktorieren zu können.
Dann helfen Unittests das zumindest der Teil der schon funktionierte nicht zerstört wird, oder es zumindest gleich erkannt wird.

Bei vernünftiger Architektur muss man davon ausgehen das alles was Public
ist, als Kontrakt für andere gedacht ist.
Wenn man also Klassen designed wird man sich ja etwas dabei denken, wenn man etwas als Private deklariert.
Diese Teile der SW sind also von vornherein als nicht von aussen benutzbar bzw. als volatile gedacht.
Sie sind also explizit dafür gedacht ggf bei refactorings "geopfert" zu werden.
Internal ist etwas anderes, denn es ist innerhalb einer Assembly ja wie Public anzusehen und stellt intern also eigentlich einen Öffentlichen Kontrakt da.
Diese Klassen sollten dann schon getestet werden.
Allerdings ist Internal wohl ähnlich wie Singleton eine meist missbrauchte Sache.

Gehen wir mal davon aus du hast für alles und jedes in deinem Projekt Unittests gemacht, also auch für jede Private Funktion.
Jetzt wird von 2 Tier auf 3 Tier erweitert, weil der Kunde mit mal Konzern wird.
Jetzt musst du eigentlich ziemlich viel refaktorieren, weil sich der Businesslayer von
einem internen, auf z.b. einen Appserver ändert.
Wenn du jetzt aber alle deine (privaten) Unittests wegschmeissen kannst, und für die neuen Privat Funktionen neue machen musst, wird bei den meisten Entwicklern dann irgendwann eine der folgenden Sachen passieren:

  1. Es wird nicht mehr vernünftig refactoriert, weil das ja die tests zerstört, also wird ggf zu viel drumherumgefrickelt statt konsequent sachen wegzuwerfen oder

  2. Die Leute haben die schn.. voll von Unittests weil ja ständig was kaputt geht und immer wieder alles doppelt gemacht werden muss, also werden irgendwann gar keine mehr gemacht.

Also ja, ich würde nur öffentliches Testen, dabei werden diese Internas ja automatisch getestet.
Und ist etwas so wichtig, das es einzeln getestet werden muss, stellt es ja eigentlich einen öffentlichen Kontrakt da, und dann sollte er auch nicht private sein.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo FZelle,

Und was nicht öffentlich ist, braucht auch nicht getestet werden.

darin sind sich ja du, spike24 und ich von Grundsatz her einig. Auch über den Zweck und Nutzen dieser Regel. Ich finde jedoch, dass das Beispiel von spike24 zeigt, dass es (wenige) bestimmte Fällen geben kann, wo es sinnvoll ist, von diesem Grundsatz abzuweichen.

herbivore

S
443 Beiträge seit 2008
vor 13 Jahren

aus einer anderen Welt ist gut

Wie herbivore sagt, bin ich auch der Meinung dass man nur öffentliches testen muss (soll?)
Wenn ich in einer Assembly nur eine Klasse habe die public ist, ist sicherzustellen dass diese ihr Verhalten nicht ändert.

Bei meinem Projekt (ORMapper) teste ich "momentan" nur klassen die ein öffentliches Interface impelementieren ... eigentlich könnte ich alle anderen klassen dann internal machen aber das ist ein anderes Thema.
ein Interface ist IConnector
und beim testen ist es mir eigentlich komplett egal woher er die daten bekommt, aus der lokalen Access datenbank oder über csv aus China und welche klassen er dafür braucht. Bei der Verwendung muss ein richtiges DataTable rauskommen.
Also privates zu testen ist vielleicht nicht sinnlos aber zuviel und unötig

In meinem Beispiel ist es eigentlich nur deswegen sinnvoll da ich sonst die doppelte Anzahl von tests gehabt hätte und ich im endeffekt zu faul war diese zu schreiben, bzw. wenn sich das XML ändert diese zu warten.
sonst halte ich auch nicht sonderlich viel davon. Ich würde mich bei einer zentralen internal Klasse vielleicht noch breitschlagen lassen wenn diese von vielen Stellen benützt wird. Aber da auch nur die Fehlerfälle damit ich diese Tests nicht bei allen x public klassen schreiben muss (d.h. Testanzahl verringern)

//Edit
@Stefan O.
Wenn private und/oder internal klassen nicht durch das testen der öffentlichen Klasse verwendet werden ... wann werden die denn sonst verwendet?

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

S
72 Beiträge seit 2009
vor 13 Jahren

@ FZelle

Danke für die ausführliche Erläuterung.
Ich versuche derzeit für mich selbst abzuklären ob es sinnvoll ist private zu testen.
Zum Beispiel wurde im "Lernen von anderen" Artikel der dotNetPro 01/2010 auch private bzw. internal getestet.

Aber ich denke auch, dass das Testen von privaten Methoden "unsinnig" ist.

@spike24

Da musst du mich missverstanden haben. Natürlich sollte es private/internal Klassen nur geben wenn Sie auch verwendet werden. Ansonsten sind sie "müll".

U
1.578 Beiträge seit 2009
vor 13 Jahren

BTW, man kann in VS auch privates testen ohne sie internal machen zu müssen, dafür gibt es den accessor.
Internal verwende ich fast nie 😁

Aber ihr meint im Prinzip das ist, wenn ich pauschal alle Methoden teste, etwas über das Ziel hinaus schieße?

Die Code Coverage Results von VS monieren auch die Privaten Methoden als "nicht getestet" 😕

Sind denn nicht die einzelnen Zwischenschritte der Privaten Methoden nicht einfacher zu verifizieren?

Wenn ich eine Methode in einer "Controller" Klasse habe, die ruft intern weitere Klassen und Aktionen auf, dann kann ich dort beim verifizieren viel schneller kleine Sachen übersehen die ich abfangen würde hätte ich die zwischen Methoden getestet.
Und nein, der Controller ist keine Monsterklasse, der ist nur der Einstiegspunkt um eine komplexe Aktion zu starten und zu steuern, einer muss das ja tun.

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo CSL,

gerade mit Blick auf den Nutzen von Unit-Tests beim Refactoring ist es kontraproduktiv, private Methoden direkt zu testen, statt nur indirekt über öffentliche Methoden, weil du dann nach einer Änderung der Implementierung die Tests nicht einfach unverändert laufen lassen kannst, um eine verlässliche Aussage über die Korrektheit der Änderungen zu bekommen, sondern die Tests erst anpassen musst.

Das bedeutet nicht nur zusätzlichen Aufwand, sondern nach der Anpassung der Test ist Qualität der Aussage über die Korrektheit nicht so gut, wie bei unveränderten Tests, denn bei der Anpassung des Tests können sich ja neue Fehler eingeschlichen haben.

herbivore