Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Unit-Test für private/protected Member? (https://www.delphipraxis.net/181788-unit-test-fuer-private-protected-member.html)

mh166 9. Sep 2014 09:00


Unit-Test für private/protected Member?
 
Hi Leute,

da ich zur Zeit versuche mir (möglichst) sauberen Code beizubringen, wollte ich gern auch Tests für mein Projekt schreiben. Sehr interessant ist dazu übrigens das Video von Nick Hodges Unit Testing in Delphi.

Soweit so gut. Habe also angefangen für meine Klasse einen Test (mit DUnitX) zu schreiben. Nun kam aber recht schnell ein Problem für mich auf: wie teste ich private Methoden? Oder wie prüfe ich den Inhalt von privaten Feldern?

Im Video sagte Nick "Only test the code that you want to work properly" — und naja, irgendwie will ich schon, dass auch private Methoden korrekt funktionieren. ;)

Ich hatte schon überlegt jeweils ne Klasse abzuleiten und darin dann eine öffentliche Zugriffsmethode auf die privaten Member zu erstellen. Aber ich denk das ist von hinten durch die Brust ins Auge. Kann ja nicht Sinn und Zweck sein. Zumal dann die Übersichtlichkeit wohl stark leidet.

Eine zweite Idee: Die TestFixture-Klasse statt von TObject von der zu testenden Klasse ableiten und so Zugriff auf die protected-Member bekommen. Aber das ist ja nochmal widersinniger: von allem guten OOP-Geistern verlassen, müsste die Klasse sich selber vorbereiten, testen und wieder freigeben. Ist ja gruselig. :pale:


Daher meine ratlose Frage an euch: wie testet man denn nun am besten private/protected Member (mit DUnitX in meinem Fall) auf korrekte Funktionsweise? Wie löst ihr das?

Sherlock 9. Sep 2014 09:06

AW: Unit-Test für private/protected Member?
 
Also meine Gedanken dazu sind folgende: Die privaten Member sind ja hoffentlich nötig, um public zu einem Ergebnis zu kommen, korrekt? Wenn das Ergebnis nach aussen also stimmt, und alle privaten Member wirklich sinnvoll gebraucht werden, dann ist doch alles in Butter.

Sherlock

Klaus01 9. Sep 2014 09:07

AW: Unit-Test für private/protected Member?
 
.. die private/protected Methoden werden nur durch die public Methoden genutzt.
Werden die dann nicht getestet wenn die public Methoden getestet werden?

Grüße
Klaus

Der schöne Günther 9. Sep 2014 09:11

AW: Unit-Test für private/protected Member?
 
Würde Delphi Namensräume kennen und einen zusätzlichen Sichtbarkeitsmodifikator (neben public, protected und private) anbieten für "Alles was in meinem Namensraum ist darf das sehen" würde man die Testklasse in den gleichen Namensraum packen und könnte alles mit dem "package"-Sichtbarkeitsmodifikator auch testen :stupid:

Namenloser 9. Sep 2014 09:18

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von mh166 (Beitrag 1271764)
Ich hatte schon überlegt jeweils ne Klasse abzuleiten und darin dann eine öffentliche Zugriffsmethode auf die privaten Member zu erstellen. Aber ich denk das ist von hinten durch die Brust ins Auge. Kann ja nicht Sinn und Zweck sein. Zumal dann die Übersichtlichkeit wohl stark leidet.

So habe ich das für protected-Methoden bisher immer gemacht. Private Methoden kann man mit keiner der beiden Varianten testen. Ich persönlich verwende die private Sichtbarkeit allerdings ungefähr so sparsam wie goto.

JasonDX 9. Sep 2014 09:20

AW: Unit-Test für private/protected Member?
 
Das Testen von privaten Methoden sollte implizit durch das Testen von public methods passieren. Teste das Verhalten einer Klasse, nicht ihren Code.

mjustin 9. Sep 2014 09:21

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von mh166 (Beitrag 1271764)
wie testet man denn nun am besten private/protected Member (mit DUnitX in meinem Fall) auf korrekte Funktionsweise? Wie löst ihr das?

Protected Methoden kann man durch eine abgeleitete Klasse, in der die Methode public re-deklariert wird, sichtbar und damit testbar machen.

Uwe Raabe 9. Sep 2014 09:30

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von JasonDX (Beitrag 1271771)
Das Testen von privaten Methoden sollte implizit durch das Testen von public methods passieren. Teste das Verhalten einer Klasse, nicht ihren Code.

Genau! Das hat den Vorteil, daß man die Tests unverändert beibehalten kann, wenn sich die Implementation der Klasse ändert. Ist das nicht eigentlich auch der Sinn von Unit-Tests, daß sie über das interne Vorgehen keine Ahnung haben (müssen)?

Man kann sich das auch so vorstellen: Schreibe die Tests so, daß du die zu testende Klasse durch eine andere Klasse ersetzen kannst, die das gleiche Interface bereitstellt und die gleiche Funktionalität hat.

mh166 9. Sep 2014 09:35

AW: Unit-Test für private/protected Member?
 
An sich habt ihr schon recht: durch das Testen der public Methoden wird implizit auch der Rest getestet. Aber zur Lokalisierung von Fehlern wäre es ja doch einfacher, wenn man gleich weiß, wos kracht als wenn man in der Public-Methode dann erst debuggen muss, bei welcher Aktion es denn nun warum genau kracht? Ginge ja auch in Richtung möglichst hoher Code Coverage vom Test, oder?

Aber gut, ich werds wohl wirklich so machen: Verhalten testen und nicht Code. (Der Satz stellt Unit-Tests für mich gleich in einem ganz anderen Licht dar. :idea: ) Klingt am vernünftigsten – es spart das Gebastel mit den private/protected Membern und es verkürzt den effektiven Code, da ich nicht jede Funktion einzeln testen muss.

Zacherl 9. Sep 2014 10:39

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1271769)
Würde Delphi Namensräume kennen und einen zusätzlichen Sichtbarkeitsmodifikator (neben public, protected und private) anbieten für "Alles was in meinem Namensraum ist darf das sehen" würde man die Testklasse in den gleichen Namensraum packen und könnte alles mit dem "package"-Sichtbarkeitsmodifikator auch testen :stupid:

Fun fact: Delphi kennt "package private" :D

Naja genau betrachtet ist es eher ein "Unit-private", aber vom Prinzip her funktionierts genauso. Wenn du zwei Klassen in der selben Unit deklarierst, kannst du ohne Probleme gegenseitig auf private Felder zugreifen. Wenn du das verhindern willst, musst du sie als strict private deklarieren.

Jens01 9. Sep 2014 11:29

AW: Unit-Test für private/protected Member?
 
Zitat:

An sich habt ihr schon recht: durch das Testen der public Methoden wird implizit auch der Rest getestet.
Das gilt aber nur für Klassen, die einfache Aktionen machen. Wenn die Klasse Unstetigkeiten bei besonderen Konstellationen der Daten hat, kann man das meist nur bei den privaten Methoden abtesten.
Man könnte das "private" und "protected" mit einer Compiler-Direktive zu "public" machen. Das ist zwar mehr "Methode Brechstange", aber geht. :thumb:

mh166 9. Sep 2014 11:38

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von Jens01 (Beitrag 1271804)
Man könnte das "private" und "protected" mit einer Compiler-Direktive zu "public" machen. Das ist zwar mehr "Methode Brechstange", aber geht. :thumb:

Hihi. Das klingt in der Tat nach Brechstange. :D Ich bleib für den Moment einfach erstmal beim Verhaltens-Test.

Soweit mir bekannt, sollte es aber im Moment zum Glück keine größeren Probleme mit widerspenstigen Daten geben: alles hübsches XML in regelmäßiger Form. Und ich hoffe, das bleibt auch so. :lol:

JasonDX 9. Sep 2014 11:55

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von mh166 (Beitrag 1271778)
Aber zur Lokalisierung von Fehlern wäre es ja doch einfacher, wenn man gleich weiß, wos kracht als wenn man in der Public-Methode dann erst debuggen muss, bei welcher Aktion es denn nun warum genau kracht?

Wenn man eine Methode indirekt testet, bekommt man Fehler aus dieser Methode auch nur indirekt mit - das stimmt. Dagegen hilft aber nur Implementierungs-orientiertes testen.

Zitat:

Zitat von mh166 (Beitrag 1271778)
Ginge ja auch in Richtung möglichst hoher Code Coverage vom Test, oder?

Code Coverage ist höchstens ein Tool um festzustellen, dass man zu wenig Tests hat. Es ist nicht geeignet zu begründen, man hätte ausreichend oder gar gute Tests.

Zitat:

Zitat von Jens01 (Beitrag 1271804)
Zitat:

An sich habt ihr schon recht: durch das Testen der public Methoden wird implizit auch der Rest getestet.
Das gilt aber nur für Klassen, die einfache Aktionen machen. Wenn die Klasse Unstetigkeiten bei besonderen Konstellationen der Daten hat, kann man das meist nur bei den privaten Methoden abtesten.

Alternativ:
  1. Klasse aufteilen, dass sie einfachere Aktionen durchführt
  2. Besondere Konstellationen durch entsprechende Methodenaufrufe produzieren, um den gewünschten, zu testenden Zustand zu erreichen
  3. Den zu testenden Zustand der Klasse direkt setzen, wenn entsprechende Setter zur Verfügung stehen.
Testbarkeit ist ein Element von Codequalität ;)

Jens01 9. Sep 2014 12:36

AW: Unit-Test für private/protected Member?
 
Zitat:

Alternativ:
Klasse aufteilen, dass sie einfachere Aktionen durchführt
Besondere Konstellationen durch entsprechende Methodenaufrufe produzieren, um den gewünschten, zu testenden Zustand zu erreichen
Den zu testenden Zustand der Klasse direkt setzen, wenn entsprechende Setter zur Verfügung stehen.

Testbarkeit ist ein Element von Codequalität
Ja, geht bei einfacher Kompliziertheit. Wenns mehr wird, dann geht das nicht mehr und die Qualität des Testcodes nimmt rapide ab.:wink:
Auch das Aufteilen der Klasse bringt da nichts mehr. Es geht nicht um den Umfang der Klasse, sondern wie kompliziert die Logik ist, die umgesetzt wird.
Weiterhin gibt es Unstetigkeiten, die man mit einfachen setzen von Eingangsvariablen, nicht mehr treffen kann. (also mit vertretbaren Aufwand)

JasonDX 9. Sep 2014 13:14

AW: Unit-Test für private/protected Member?
 
Es stimmt dass bei steigender Komplexität auch das Testen schwieriger wird. Dabei wird das Testen in diesen Fällen umso wichtiger, genauso wie sauberer, übersichtlicher, wartbarer - und eben testbarer - Code.

Zitat:

Zitat von Jens01 (Beitrag 1271823)
Auch das Aufteilen der Klasse bringt da nichts mehr. Es geht nicht um den Umfang der Klasse, sondern wie kompliziert die Logik ist, die umgesetzt wird.

Man kann aber auch Logik aufteilen. Meistens durch Generalisieren einer Teillogik, und separaten Implementierung (&testen) dieser. Dann kann man diese auch separat testen. Tests für die ursprüngliche Klasse können dann eine Mock-Implementierung der Teillogik verwenden, was wiederum ein einfaches gezieltes Testen ermöglicht.

Zitat:

Zitat von Jens01 (Beitrag 1271823)
Weiterhin gibt es Unstetigkeiten, die man mit einfachen setzen von Eingangsvariablen, nicht mehr treffen kann. (also mit vertretbaren Aufwand)

Vllt. nicht mit direktem setzen von Eingangsvariablen, aber man kann auf getestete Methoden zurückgreifen:

Code:
testInstance = TestClass.create('testValue');
testInstance.doSomething('withTestValue');

testInstance.testTargetMethod('anothertestvalue');
entsprechend muss transferToState getestet sein, aber dann sollte das Problem auch lösbar sein.

Mikkey 9. Sep 2014 13:19

AW: Unit-Test für private/protected Member?
 
Ich würde den Ansatz von Zacherl bevorzugen.

In C# haben wir die Möglichkeit genutzt, Klassen als "partial" zu definieren. Die Unit-Tests haben dann einfach die Klasse ergänzt.

Da Delphi alle Methoden einer Klasse in einer Quelldatei erwartet, sehe ich als einzige Möglichkeit, die Unit-Tests dort ebenfalls hineinzuschreiben. Im Relase lassen sich die Bereiche ja per ifdef ausblenden.

Ganz schlecht wäre m.E. Code im Unit-Test-Fall zu modifizieren, da läuft man ganz schnell Gefahr, etwas Anderes zu testen als den Programmcode. Und - ein Unit-Test soll eine Methode testen, das ist in der Regel nicht eine komplexe Funktion, die gerade noch public erreichbar ist.

Jens01 9. Sep 2014 13:36

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von JasonDX (Beitrag 1271826)
Vllt. nicht mit direktem setzen von Eingangsvariablen, aber man kann auf getestete Methoden zurückgreifen:
Code:
testInstance = TestClass.create('testValue');
testInstance.doSomething('withTestValue');
testInstance.testTargetMethod('anothertestvalue');
entsprechend muss transferToState getestet sein, aber dann sollte das Problem auch lösbar sein.

Sorry, kann ich gerade nicht nachvollziehen, was Du meinst.

Dejan Vu 9. Sep 2014 13:55

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von JasonDX (Beitrag 1271826)
Es stimmt dass bei steigender Komplexität auch das Testen schwieriger wird.

Eigentlich nicht. Es bleiben -im Idealfall- kleine leicht testbare Klassen. Nur eben viel mehr. Aber das Testen selbst wird nicht komplexer, es dauert nur länger. Wir *machen* nur den Fehler, und lassen große Projekte immer komplexer werden, weil wir hier noch was ranbepseln, dort eine Funktion anflanschen usw.

Wichtig ist, das man Sperenzchen wie Threads und solchen Schnickschnack soweit wie möglich vermeidet, denn so ein Zeugs ist verdammt schwer zu testen. Wenn man Threads benutzen muss, dann am besten mit einem fertigen Framework, wie einer Jobqueue, Workerthreads oder ähnlichem. Überhaupt sollte alles, was die heile testbare Welt verlassen kann (eine 'Unit'), gekapselt werden, also nicht wie wild SQL-Befehler absetzen, wo es gerade passt oder eine Verbindung zu einer anderen Dimension herstellen.

Zacherl 9. Sep 2014 14:02

AW: Unit-Test für private/protected Member?
 
Unter dem Aspekt, dass Klassen in der selben Unit gegenseitig auf private und protected Felder zugreifen können, hatte ich es mal folgendermaßen realisiert:
  1. "Unit Test"-Unit anlegen mit ner Basisklasse TUnitTest und einer RegisterUnitTest Funktion
    • Die Basisklasse bekommt eine abstrakte virtuelle Methode Test
  2. In jeder Unit in der man eine oder mehrere Klassen testen willst, bindet man (unter Verwendung von IFDEF xxx) die "Unit Test"-Unit ein und deklariert sich eine Testklasse, die von TUnitTest ableitet.
    • Jetzt kann man die virtuelle Test Methode überschreiben und fleißig testen.
  3. Im initialization Teil der Unit ruft man zum Schluss noch schnell RegisterUnitTest für jede vorhandene Testklasse auf.

In der Hauptunit implementiert man sich die RegisterUnitTest Funktion im Optimalfall so, dass alle Testobjekte in einer Liste abgelegt werden, die man dann beim großen Test einfach sequentiell durcharbeitet.

JasonDX 9. Sep 2014 14:06

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von Mikkey (Beitrag 1271827)
Und - ein Unit-Test soll eine Methode testen, das ist in der Regel nicht eine komplexe Funktion, die gerade noch public erreichbar ist.

Nein, ein Unit-Test soll nicht eine einzelne Methode testen. Das Aufrufen von einzelnen Methoden geschieht deshalb, weil diese Methoden das Verhalten der Implementierung definieren. Dieses Verhalten ist, was eigentlich getestet wird.
Es gibt für jede Spezifizierung einer Klasse mehrere korrekte Implementierungen. Ein Unit-Test soll nicht prüfen ob eine bestimmte dieser korrekten Implementierungen verwendet wurde, sondern ob es sich überhaupt um eine korrekte Implementierung handelt, und beschreibt bei falschen Implementierungen, welche Verhaltensanforderung nicht erfüllt wurde.


Zitat:

Zitat von Jens01 (Beitrag 1271828)
Zitat:

Zitat von JasonDX (Beitrag 1271826)
Vllt. nicht mit direktem setzen von Eingangsvariablen, aber man kann auf getestete Methoden zurückgreifen:
Code:
testInstance = TestClass.create('testValue');
testInstance.doSomething('withTestValue');
testInstance.testTargetMethod('anothertestvalue');
entsprechend muss transferToState getestet sein, aber dann sollte das Problem auch lösbar sein.

Sorry, kann ich gerade nicht nachvollziehen, was Du meinst.

Es geht ums Testen von Methoden einer Klasse, die einen bestimmten Zustand beschreibt, und wie man diesen Zustand in einem Unittest erreicht.
Mein Beitrag ging darauf ein, dass das Erreichen dieses Zustandes auch mit Hilfe von bereits getesteten Methoden der Klasse geschehen kann.


Zitat:

Zitat von Dejan Vu (Beitrag 1271831)
Zitat:

Zitat von JasonDX (Beitrag 1271826)
Es stimmt dass bei steigender Komplexität auch das Testen schwieriger wird.

Eigentlich nicht. Es bleiben -im Idealfall- kleine leicht testbare Klassen. Nur eben viel mehr. Aber das Testen selbst wird nicht komplexer, es dauert nur länger. Wir *machen* nur den Fehler, und lassen große Projekte immer komplexer werden, weil wir hier noch was ranbepseln, dort eine Funktion anflanschen usw.

Da hast du an sich recht, ich hab mich auch weng falsch ausgedrückt. Das, was im Endeffekt schwieriger wird, ist die saubere Zerteilung eines komplexen Problems in kleinere, einfache Teilprobleme.

Sir Rufo 9. Sep 2014 14:24

AW: Unit-Test für private/protected Member?
 
Das Testen der
Delphi-Quellcode:
private
und
Delphi-Quellcode:
protected
Methoden ist in meinen Augen völliger Unfug. Wie die Klasse intern funktioniert ist sowas von egal, sie muss lediglich nach aussen so reagieren, wie vereinbart und durch die Unit-Tests sichergestellt wird.

Wird die Klasse irgendwann mal umgestaltet (bei gleicher Aussenwirkung) dann fliegt einem sofort der Unit-Test um die Ohren obwohl die Anwendung damit weiterhin zurechtkommt (für die hat sich ja nichts verändert).

Der Unit-Test hat auch immer nur eine bedingte Aussagekraft und ist nicht die Lösung für alle Probleme der Programmierwelt. Sicherheitslücken, Speicherlecks, etc. kann man damit nicht entdecken.

Dejan Vu 9. Sep 2014 14:54

AW: Unit-Test für private/protected Member?
 
Delphi-Quellcode:
Procedure TFoo.PublicMethodToTest;
var
  list : TSomeList;

Begin
  list := PrivateLoaderOfTheList();
  for item in list do PrivateModifierOfItem(item);
  PrivateSaveTheList();
End;
Klar, ich kann die Liste von außen übergeben. Klar. Ich kann die Liste auch selbst speichern. Aber -verdammt- so lautet der Auftrag und die Spezifikation. "Die Methode lädt eine Liste, modifiziert die Elemente nach Schema F und speichert sie wieder ab".

Wäre doch viel einfacher, wenn ich den 'PrivateModifierOfTheItem' testen könnte. Das der das für alle Elemente einer Liste macht, sieht ein Blinder mit nem Krückstock (<= Legitimer Pragmatismus). Wenn alle Methoden halbwegs sichbar sind, kann ich die vielleicht sogar mocken und spar mir den Pragmatismus mit einem 5-Zeiler.

Soll ich nun den 'PrivateModifierOfTheItem' in eine extra Klasse auslagern, nur damit man den Testen kann? Ist doch bescheuert und außerdem wären wir dann wieder bei der prozeduralen Programmierung, die eigentlich seit 25 Jahren out ist. Ich glaube, hier ist die Frage des TE berechtigt.

Ich würde diese Methode 'PrivateModifierOfItem' protected machen, einen TestklassenWrapper deklarieren, der die Methode public macht und das dann über den Testwrapper testen. Nicht 100% clean, weil ja der TestWrapper getetstet wird und nicht die Klasse selbst, aber das ist ok.

JasonDX 9. Sep 2014 15:26

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von Dejan Vu (Beitrag 1271839)
Klar, ich kann die Liste von außen übergeben. Klar. Ich kann die Liste auch selbst speichern. Aber -verdammt- so lautet der Auftrag und die Spezifikation. "Die Methode lädt eine Liste, modifiziert die Elemente nach Schema F und speichert sie wieder ab".

Und woher läd die Klasse diese Liste? Diese Quelle abstrahieren (sollte man eh), und schon kann man einen sauberen Test schreiben, der nicht nur eine Methode testet - die nichtmal zwingend existieren muss - sondern die geforderte Funktionalität verifiziert, ohne dass man in die Klasse reingucken muss, oder sonst irgendwelche dreckigen Tricks draufschmeißt. Ist eigentlich gar nicht so schwer :)

Stevie 9. Sep 2014 15:27

AW: Unit-Test für private/protected Member?
 
@Dejan Vu:
Irgendwo wird aber diese Klasse mit der Außenwelt reden, wird Daten bekommen haben und irgendwelche Daten ausgeben. Und darüber kann sehr wohl getestet werden, ob deine Methode, die intern rumwurschtelt, richtig gearbeitet hat. Und dazu muss man keine Interna nur für Unittest Zwecke offen legen.

Nicht umsonst ist Clean Code kein Selbstzweck, sondern u.a. dazu da testbaren Code zu schreiben.

hoika 9. Sep 2014 17:28

AW: Unit-Test für private/protected Member?
 
Hallo,

"Die Methode lädt eine Liste, modifiziert die Elemente nach Schema F und speichert sie wieder ab".

OK.
Die Methode lädt eine Liste -> Dateiname wird beim Test übergeben, damit kann der Test eine "Liste" bauen, die er kennt

modifiziert die Elemente nach Schema F -> interessiert hier nicht, es muss eine Public-Methode "ModifiziereNachSchemaF" geben, die ruft der Test auf

und speichert sie wieder ab -> aha, wir haben die Änderung, also lädt der Test die Datei und prüft, ob die Änderung korrekt ist


Alles andere ist bereits gesagt, Tests sind BlackBox-Tests, wie die Klasse das intern macht, hat den Test nicht zu interessieren.

Aber:
Liegt die Test-Klasse in der gleichen Unit, wie die zu testende Klasse,
kommt sie dann nicht an die private's ran (das wäre quasi eine "friend"-Implementation.


Heiko

Dejan Vu 9. Sep 2014 19:19

AW: Unit-Test für private/protected Member?
 
Wie ich die Klasse testen würde, muss ich ja keinem erzählen. Und das die Klasse so testbar ist, auch nicht. Der einfachste und den Code am wenigsten verändernde Weg wäre der, die private Methode zu testen. Alles andere würde Mocking bedeuten, oder Refactoring, oder beides. Wenn ich entsprechende Helfe habe: Super, die Load-Methode gemockt, um ein Element zu liefern, die Save-Methode deaktiviert und fertig.

Aber ohne Mocking?

Die Aussage war 'private Methoden müssen nicht getestet werden' und ich habe ein Beispiel gebracht, wo das doch sinnvoll wäre. Es ist ja nicht so, das man jeden Tag seine Klassen so schreiben kann, das man sie super testen kann. Meist ist es so, das man legacy Code hat, und nachträglich Tests erstellen muss, um das Kartenhaus zu stabilisieren. Und das man ausgelieferten Code nicht einfach mal so umschreibt, um ihn testbar zu machen, versteht sich ja von selbst. Modifizierer ändern geht gerade, aber selbst bei einem Refactoring würde ich 2x überlegen, ob ich das mache.

Also: Die Klasse *sieht* so aus und ich kann die Methode, die die Liste erstellt, nicht mocken. Weil ich nichts zum mocken habe, verdammt. Also, was bleibt? Die private Methode testen. Und wie teste ich die? Womit wir wieder beim Thema wären. :mrgreen:

Zitat:

Zitat von Stevie (Beitrag 1271848)
Und darüber kann sehr wohl getestet werden, ob deine Methode, die intern rumwurschtelt, richtig gearbeitet hat.

Mit Mocking: Ja. Sonst: Nein.
Zitat:

Zitat von hoika (Beitrag 1271872)
Die Methode lädt eine Liste -> Dateiname wird beim Test übergeben

Das ist kein Unit-Test, denn es werden Systemgrenzen überwunden. Fällt also weg. Außerdem kommen die Daten im Beispiel von einer Quelle, die man nicht simulieren kann. Blöd. Legacy eben.
Zitat:

Zitat von hoika (Beitrag 1271872)
modifiziert die Elemente nach Schema F -> interessiert hier nicht,

Na doch. Du schreibst den Test ja gerade, um die Einhaltung von 'Schema F' zu verifizieren und für die Zukunft zu garantieren.

Nur mal so: Wenn ich testbaren Code schreibe, würde ich eine TItemModifier-Klasse bauen, und diese separat testen. Aber wenn ich diesen Code, so wie er ist, testen müsste, würde ich den 'PrivateModifierOfItem' protected machen, eine Testklasse drumherum bauen und diese testen. Das ändert die Funktionalität garantiert nicht.

Testcode neben dem zu testenden Code ist blöd. Das sollte man nicht machen.

BUG 9. Sep 2014 20:15

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von JasonDX (Beitrag 1271809)
Dagegen hilft aber nur Implementierungs-orientiertes testen.

Assertions sind gegebenenfalls auch ziemlich praktisch, um die Konsistens des Zustandes einer Klasse festzustellen.
Im Testcode sollten die wohl aktiviert sein :wink:

Stevie 9. Sep 2014 20:50

AW: Unit-Test für private/protected Member?
 
Haaaalt, stop! Lasst uns bitte nicht vom Thema abdriften sondern uns nochmal vor Augen holen, was die Frage und Ausgangslage im ersten Post war (Markierungen von mir):
Zitat:

Zitat von mh166 (Beitrag 1271764)
da ich zur Zeit versuche mir (möglichst) sauberen Code beizubringen, wollte ich gern auch Tests für mein Projekt schreiben. Sehr interessant ist dazu übrigens das Video von Nick Hodges Unit Testing in Delphi.

Soweit so gut. Habe also angefangen für meine Klasse einen Test (mit DUnitX) zu schreiben. Nun kam aber recht schnell ein Problem für mich auf: wie teste ich private Methoden? Oder wie prüfe ich den Inhalt von privaten Feldern?

Im Video sagte Nick "Only test the code that you want to work properly" — und naja, irgendwie will ich schon, dass auch private Methoden korrekt funktionieren. ;)

Hier ist nicht die Frage nach Unittests in Legacy Code (da hätte man auch wohl direkt die entsprechende Lektüre empfohlen), sondern Clean Code und Unit Tests.
Und da steht meine Aussage: Clean Code bedeutet testbarer Code, testbarer Code bedeutet in Isolation testbarer Code, in Isolation testbarer Code bedeutet öffentliche API und nix anderes

hoika 9. Sep 2014 21:32

AW: Unit-Test für private/protected Member?
 
Hallo,

also sorry, ich habe es nicht begriffen!
Wo ist denn nun das Problem?

Es gibt eine Klasse, die wird von einem Programm benutzt.
Das Programm muss also die Klasse mit Daten füttern.
Als Ergebnis liefert die Klasse irgendwas zurück.

Wo ist das Problem?

Die Testaufgabe muss doch heißen
"Funktioniert die Klasse?"


Heiko

JasonDX 10. Sep 2014 06:43

AW: Unit-Test für private/protected Member?
 
Zitat:

Zitat von Dejan Vu (Beitrag 1271890)
Die Aussage war 'private Methoden müssen nicht getestet werden' und ich habe ein Beispiel gebracht, wo das doch sinnvoll wäre.

Die Aussage ist auch falsch - richtig wäre: private Methoden müssen nicht direkt, sondern sollten implizit getestet werden.

Ja, wer einen Haufen Mist als Legacy-Code hat, kann Clean-code-Paradigmen nicht immer folgen - da kann man dann auch nichts anderes machen als den Haufen durch Tests höher stapeln, und sich baldmöglichst um ein Refactoring kümmern.

Dejan Vu 10. Sep 2014 08:01

AW: Unit-Test für private/protected Member?
 
Korrekt. Man muss wirklich unterscheiden zwischen:
  • Legacy-Code 'as is', bei dem man mit möglichst wenig Trickserei akzeptable Tests bekommt.
  • Neuen Code, wo ich mit den entsprechenden Programmierparadigmen perfekte(*) Tests bekommen kann.

(*) Perfekt <> 100% Coverage !


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz