Test Driven Development (Teil 3 von 3)
Kommentare
Ansicht der Kommentare:
(Linear | Verschachtelt)
mitch am um :
Heute wurde mir folgender Artikel von Heise Developer zugespielt: http://www.heise.de/developer/artikel/Funktionsweise-und-Zusatznutzen-von-Strict-TDD-3342583.html
Der erschien einen Tag vor meinem Blogartikel, da hätte ich mir das ja auch sparen können ;-) Immerhin bestätigt er mich inhaltlich. "Obvious Implementation" habe ich vergessen zu erwähnen, bei "Triangulation" laufen die Definitionen etwas auseinander, der Rest passt.
Was mich gerade überrascht: Der Autor des Artikels kommt von codecentric und dazu fällt mir sofort ein "hey, die waren auch auf der SoCraTes 2016" und "hey, die veranstalten den Global Day of Coderetreat in München (und sind gnadenlos überbucht").
Der erschien einen Tag vor meinem Blogartikel, da hätte ich mir das ja auch sparen können ;-) Immerhin bestätigt er mich inhaltlich. "Obvious Implementation" habe ich vergessen zu erwähnen, bei "Triangulation" laufen die Definitionen etwas auseinander, der Rest passt.
Was mich gerade überrascht: Der Autor des Artikels kommt von codecentric und dazu fällt mir sofort ein "hey, die waren auch auf der SoCraTes 2016" und "hey, die veranstalten den Global Day of Coderetreat in München (und sind gnadenlos überbucht").
Jue am um :
Sehr interessante Artikelserie! Danke!
Zwei Fragen beschäftigen mich noch; und vielleicht kannst du diesen Knoten bei mir im Kopf lösen. Ich versuche es mal zu beschreiben:
1) Wie gehst du mit Abhängigkeiten um? Letztlich hat man zwischen den Klassen viele Abhängigkeiten: Klasse A nutzt Klasse B, die wieder Klasse C nutzt.
Ich bin jemand, der häufig bei C anfängt und sich dann zu A hocharbeitet. Zumindest wenn das Problem vorher schon gut überblickbar ist und ein grober Plan steht, wie ich mein großes Problem in kleine Teilprobleme aufspalte.
Schreibst du Mocks, die das Verhalten der Klassen mimen? Oder lässt du die Abhängigkeiten einfach bestehen und fängst mit den Tests bei A an und wenn keiner gegen die Wand fährt, testest du bei B weiter, das dann ein funktionierendes A voraussetzt?
2) Wie gehst du mit Abhängigkeiten zu externen Librarys um? Derzeit versuche ich (bzw. gerade ist das Projekt pausiert) einen Treiber für Mesh-Netzwerke zu schreiben. So richtige Unit-Tests habe ich dabei aber nicht geschrieben, da einfach sehr viel Logik in der TLS-Library steckt und ich keinen Nerv darauf hatte Netzwerkaktivitäten zu mocken. Zumal ich bezweifle, dass ich das Verhalten der TLS-Libaray ausreichend realitätnah nachgespielt bekomme. Mein Plan ist es, direkt einen Integration-Test zu schreiben, der mit Hilfe der Network-Namespaces von Linux verschiedene Netzteilenehmer simuliert. Somit bekommt jeder Node eine eigene IP und kann die anderen Nodes über eine Netzwerkbrücke sehen.
Ich hoffe, du verstehst was ich meine. Und vielleicht hast du eine Idee, wie ich das Problem löse.
LG Jue
Zwei Fragen beschäftigen mich noch; und vielleicht kannst du diesen Knoten bei mir im Kopf lösen. Ich versuche es mal zu beschreiben:
1) Wie gehst du mit Abhängigkeiten um? Letztlich hat man zwischen den Klassen viele Abhängigkeiten: Klasse A nutzt Klasse B, die wieder Klasse C nutzt.
Ich bin jemand, der häufig bei C anfängt und sich dann zu A hocharbeitet. Zumindest wenn das Problem vorher schon gut überblickbar ist und ein grober Plan steht, wie ich mein großes Problem in kleine Teilprobleme aufspalte.
Schreibst du Mocks, die das Verhalten der Klassen mimen? Oder lässt du die Abhängigkeiten einfach bestehen und fängst mit den Tests bei A an und wenn keiner gegen die Wand fährt, testest du bei B weiter, das dann ein funktionierendes A voraussetzt?
2) Wie gehst du mit Abhängigkeiten zu externen Librarys um? Derzeit versuche ich (bzw. gerade ist das Projekt pausiert) einen Treiber für Mesh-Netzwerke zu schreiben. So richtige Unit-Tests habe ich dabei aber nicht geschrieben, da einfach sehr viel Logik in der TLS-Library steckt und ich keinen Nerv darauf hatte Netzwerkaktivitäten zu mocken. Zumal ich bezweifle, dass ich das Verhalten der TLS-Libaray ausreichend realitätnah nachgespielt bekomme. Mein Plan ist es, direkt einen Integration-Test zu schreiben, der mit Hilfe der Network-Namespaces von Linux verschiedene Netzteilenehmer simuliert. Somit bekommt jeder Node eine eigene IP und kann die anderen Nodes über eine Netzwerkbrücke sehen.
Ich hoffe, du verstehst was ich meine. Und vielleicht hast du eine Idee, wie ich das Problem löse.
LG Jue
mitch am um :
Danke, das freut mich!
Zu 1:
Bei sehr einfachen Dingen benutze ich auch im Test echte andere Klassen: Hauptsächlich bei Datenobjekten/Beans, die nur aus Gettern/Settern bestehen und deshalb keinen eigenen Test bekommen. So kriegt man noch etwas Codeabdeckung hin (und erkennt überflüssige Attribute, wenn die Getter/Setter im Test nie aufgerufen werden).
Manchmal arbeite ich auch mit echten anderen Klassen, die ihrerseits keine weiteren Abhängigkeiten haben, wenn das an der Stelle einfacher/schneller/übersichtlicher als ein Mock oder Stub ist. Das verstößt aber bestimmt gegen irgendeine eine Form der Reinen Lehrte™.
Wenn ich aber eine Klasse A teste, die ihrerseits aber auf die Klassen B und C zugreift, die ihrerseits mit Instanzen der Klassen D, E und F versorgt werden wollen, damit es keine NullPointerExceptions gibt, dann hört für mich der Spaß auf und es wird gemockt oder gestubbt.
Zu 2:
Hmm, das hängt wohl von der Library ab…
Unser firmeninternes Framework ist in der aktuell noch genutzten Inkarnation nicht besonders Unit-Test-freudig, dafür habe ich mal einen Haufen Stubs geschrieben, die die Interfaces ghettomod-mäßig nachimplementieren (und auch nur jeweils genau die Funktionen, die mein Projekt benutzt). Das war zwar rückblickend etwas Aufwand, dafür sind wir aber auch testfähig.
Für Teile unserer Oberfläche nutzen wir Vaadin. Dem ist es recht egal, ob es auf einem echten Webserver oder lokal im Unit-Test läuft, da können wir einfach mit den echten Vaadin-Klassen testen und z.B. Buttons in einem Testfall fragen, ob sie gerade enabled oder visible sind.
Bei Deinem Fall weiß ich nicht, wie es da drumherum aussieht. Die Integrationstestfälle klingen auf jeden Fall schon mal interessant :-)
Eine ganze TLS-Library zu mocken klingt hingegen nicht so toll.
Das Wunderwaffenallheilmittel für „Test zu kompliziert“ scheint „zerteil Dein Testobjekt“ zu sein. Ich kenne da deine Architektur nicht, aber vielleicht kann man die TLS-Teile soweit rausoperieren, dass die nur in einer dünnen Wrapper-Schicht zwischen Deinem eigentlichen Code und der TLS-Library liegen. Dann musst Du nur noch die (hoffentlich wenigeren) Aufrufe in deine Wrapperschicht wegmocken.
Die Unit-Testfälle für die Wrapper-Schicht bleiben dabei u.U. genauso doof wie vorher (also weglassen ;-), aber Du hast kannst vielleicht die andere Hälfte Deines Codes testen. Wäre doch schon mal was.
Keine Ahnung, ob das für Dich passt, aber vielleicht geht das in die richtige Richtung.
so long
Mitch
Zu 1:
Bei sehr einfachen Dingen benutze ich auch im Test echte andere Klassen: Hauptsächlich bei Datenobjekten/Beans, die nur aus Gettern/Settern bestehen und deshalb keinen eigenen Test bekommen. So kriegt man noch etwas Codeabdeckung hin (und erkennt überflüssige Attribute, wenn die Getter/Setter im Test nie aufgerufen werden).
Manchmal arbeite ich auch mit echten anderen Klassen, die ihrerseits keine weiteren Abhängigkeiten haben, wenn das an der Stelle einfacher/schneller/übersichtlicher als ein Mock oder Stub ist. Das verstößt aber bestimmt gegen irgendeine eine Form der Reinen Lehrte™.
Wenn ich aber eine Klasse A teste, die ihrerseits aber auf die Klassen B und C zugreift, die ihrerseits mit Instanzen der Klassen D, E und F versorgt werden wollen, damit es keine NullPointerExceptions gibt, dann hört für mich der Spaß auf und es wird gemockt oder gestubbt.
Zu 2:
Hmm, das hängt wohl von der Library ab…
Unser firmeninternes Framework ist in der aktuell noch genutzten Inkarnation nicht besonders Unit-Test-freudig, dafür habe ich mal einen Haufen Stubs geschrieben, die die Interfaces ghettomod-mäßig nachimplementieren (und auch nur jeweils genau die Funktionen, die mein Projekt benutzt). Das war zwar rückblickend etwas Aufwand, dafür sind wir aber auch testfähig.
Für Teile unserer Oberfläche nutzen wir Vaadin. Dem ist es recht egal, ob es auf einem echten Webserver oder lokal im Unit-Test läuft, da können wir einfach mit den echten Vaadin-Klassen testen und z.B. Buttons in einem Testfall fragen, ob sie gerade enabled oder visible sind.
Bei Deinem Fall weiß ich nicht, wie es da drumherum aussieht. Die Integrationstestfälle klingen auf jeden Fall schon mal interessant :-)
Eine ganze TLS-Library zu mocken klingt hingegen nicht so toll.
Das Wunderwaffenallheilmittel für „Test zu kompliziert“ scheint „zerteil Dein Testobjekt“ zu sein. Ich kenne da deine Architektur nicht, aber vielleicht kann man die TLS-Teile soweit rausoperieren, dass die nur in einer dünnen Wrapper-Schicht zwischen Deinem eigentlichen Code und der TLS-Library liegen. Dann musst Du nur noch die (hoffentlich wenigeren) Aufrufe in deine Wrapperschicht wegmocken.
Die Unit-Testfälle für die Wrapper-Schicht bleiben dabei u.U. genauso doof wie vorher (also weglassen ;-), aber Du hast kannst vielleicht die andere Hälfte Deines Codes testen. Wäre doch schon mal was.
Keine Ahnung, ob das für Dich passt, aber vielleicht geht das in die richtige Richtung.
so long
Mitch
adni am um :
na endlich ist der 3. Teil raus :-) danke danke :-) lg Adni
Mitch’s Manga Blog am : Test Driven Development (Teil 2 von 3)