Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > de.comp.lang.java > #13013
| From | Wanja Gayk <brixomatic@yahoo.com> |
|---|---|
| Newsgroups | de.comp.lang.java |
| Subject | Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle |
| Date | 2016-07-18 00:33 +0200 |
| Organization | Aioe.org NNTP Server |
| Message-ID | <MPG.31f6261eb408512e9896be@news.aioe.org> (permalink) |
| References | <du7ob7Fecu7U1@mid.individual.net> <1467923825.579226@alpaka.in-berlin.de> <MPG.31ea26fc280e77349896bc@news.aioe.org> <nlp8pd$js5$1@newsreader4.netcologne.de> |
In article <nlp8pd$js5$1@newsreader4.netcologne.de>, Patrick Roemer
(sangamon@netcologne.de) says...
>
> Responding to Wanja Gayk:
> > Manchmal programmiert man ohne klares Ziel, weil das noch nicht in Sicht
> > ist und man sich langsam voran tastet, bzw. baut man wärend der
> > Implementation sehr oft noch sehr viel um, refactored eine Menge und man
> > will dafür nicht immer die Tests komplett umbauen, weil sich die API
> > ändert (weil man auf halbem Wege merkt, dass sie doch nicht so elegant
> > war, wie man dachte und einem was besseres einfällt).
>
> Aber wie merkt man das denn ohne Tests (oder sonstigen Code der mit dem
> API arbeitet)? :)
Nicht jede Methode ist Teil einer öffentlichen API, sondern das meiste
Zeug ist private (bzw. package private) oder Teil einer groben Idee.
Beispiel: Ich will ne Liste von Objekten zusammen stellen, die sich aus
irgendeinem Zustand ergibt (Zeilen aus einer tabelle, Artikel, bestimmte
Objekte aus einer größeren Masse von Objekten, egal).
Du machst also ne einfache Methode, die sieht so aus:
List<Something> getSomethings(){...}
Schön, sieht erstmal richtig aus, sieht auch nicht so schwer aus, tut
wahrscheinlich was es soll, man freut sich. Werde da bei Gelegenheit
einen Test für schreiben, um sicher zu gehen, aber jetzt geht's erstmal
weiter mit dem Code, der das dann benutzt,vielleicht fällt dann ja was
auf.
Dann merke ich: Nah, also eine Liste zu liefern war irgendwie blöd, weil
ein Set da klarer wäre, obwohl: wenn ich die Duplikate sehen will, wäre
es sinnvoll eine Liste einem Set gegenüber zu stellen.. will ich
duplikate loggen oder nicht? Will ich vielleicht ne LinkedList haben,
und billig vorne was einfügen können? Weiß ich noch nicht so genau, aber
es erscheint mir ne gute Idee zu sein, wenn ich erstmal eine Collection
im Parameter mitgebe, dann kann ich mir später als Aufrufer aussuchen,
was für eine Collection ich befüllen will.
Also wird daraus:
<T extends Collection<? super Something>> T getSomethings(T target){...}
Schön, sieht richtig aus, mache ich dann einen Test für, wenn es mir
passt, erstmal weiter gehen..
Dann merke ich: Okay, hier benutze ich das Stück nochmal, aber das hier:
Set<Something> someThings = getSomethings(new HashSet<Something>());
Set<OtherThings> otherThings = new HashSet<>();
for(Something s : someThings){
otherThings.add(toOtherThing(s));
}
...ist irgendwie blöd jetzt, ich packe alles in meine Collection und
muss dann nochmal drüber iterieren, um es auf was anderes zu mappen,
besser ich gebe der Methode nicht nur Zielcollection mit, sondern
zusätzlich eine Mapping-Funkction dann muss ich nur einmal drüber
iterieren und der Aufrufer, der das schon benutzt, der übergibt einfach
ne Identity-Funktion und ist fein raus, oder ich mache ihm eine neue
Methode mit der alten Signatur, die einfach weiter delegiert und eine
Identity-Funktion als Parameter übergibt, damit wird der Aufrufer
lesbarer:
Also wird daraus:
<T extends Collection<? super Something>> T getSomethings(T target){
return getSomethings(target, Function.identity());
}
<U, T extends Collection<? super U>> T getSomethingsFunction<? super
Something, U> mapper, T target){...}
Und der Code oben wird zu:
Set<OtherThings> otherThings = getSomethings(myClass::toOtherThing, new
HashSet<OtherThings>());
Hätte ich diese Entwicklung "test first" geschrieben, also mit allen
Corner cases, hätte ich jeden der Tests für diese Methode (und das kann
ein ganzer Batzen sein) zweimal umschreiben müssen. So sehe bin ich bei
etwas angekommen, wo ich denke: okay, das sollte reichen.
Entweder schreibe ich jetzt einen Test, oder wenn mich noch das
"höhere" Ziel quält, wegen dem ich diese Methode überhaupt geschrieben
habe, kann es sein, dass ich das erst zuende machen muss, um den Faden
nicht zu verlieren.
Also mache ich mit meiner Idee erstmal weiter, bis ich zu dem Punkt
komme, wo ich denke dass es jetzt "soweit funktionieren sollte, dass ich
es testen kann", weil ich keine größeren Änderungen mehr erwarte und
dann schreibe ich Tests. Zunächst für das grobe Zeug, dann für das
feinere Zeug. Ich präzisiere dann meine Erwartungen immer genauer und
die Tests sagen mir, ob ich richtig liege, oder einen Hund drin habe.
Meine Entwicklung sieht in der Regel so aus:
1.Hack
2.Refine
do{
3.Write Test
4.Fix Bugs
}while (bugs detected || tests incomplete)
Üblicherweise beschränkt auf ein System von 1 bis 4 Klassen, bzw. auf
ein bis drei Milestones auf meiner Todo-Liste.
Ein Test zurrt mir die API einer Methode fest, macht Änderungen teurer,
schränkt mich ein. Derart Entscheidungen verschiebe ich gerne auf
später.
Ein Reihe Tests, die ich nach einem halben Tag wieder löschen kann, weil
ich merke, dass ich auf dem Weg eine bessere Lösung für ein Problem
gefunden habe ("oh der Workaround ist eigentlich ziemlich cool, da
brauche ich diese 5 Methoden eigentlich gar nicht mehr.."), ist
verschwendete Zeit, die verbringe ich lieber am Problem oder in der
Teeküche, um den Kopf wieder frei zu kriegen.
> Natürlich lege ich auch erst mal explorativ los, und schreibe ganz
> bestimmt nicht erst mal für jede Zeile "Produktivcode" einen Test, der
> diese erzwingt. Aber ich will relativ bald ein Gefühl dafür bekommen,
> wie sich so ein API anfühlt - und den explorativen Code dafür schreibe
> ich doch lieber gleich als Testcases.
Letzteres ist bei mir high level. Beispiel: Ich brauche einen REST Web
Service, der mir irgendwelche Kunden zurück liefert. Der Test ist
einfach: HTTP connection aufmachen, Kundennummer rein geben, kommt der
Kunde zurück? Stimmen die Fehlermeldeungen? Das will ich ja nicht jedes
mal immer neu ausprobieren und mit dem Browser oder CURL rumlutschen, da
soll einmal Knöpfchen drücken genügen. Also Test schreiben, dann
implementieren. Da weiß ich, was ich will, im voraus.
Und dann hast du Aufgaben, wie: Ich suche alle Files in einem Directory,
extrahiere daraus irgendwelche Daten, cache die, ggf. muss ich per
Timestamps prüen, ob sich was in einem File geändert hat, damit ich den
neu einlese, etc. Da ergeben sich Fragen, wie: Wie halte ich die Daten,
wie die Relation der Daten zu den Files und den Timestamps, bzw. brauche
ich read-write-locks, was passiert, wenn ein File gelöscht wird, oder
whatever.. und da weiß man ggf. noch nicht ganz genau, was man will und
was das Sinnvollste ist. Mit anderen Worten wird erstmal explorativ
drauflos gehackt und geschaut, wie sich das verhält und ob man das so
nehmen kann, oder ob was anderes besser wäre, etc. und der einzige
"Test" bis dahin hat die Qualität einer hingerotzen Main-Methode, nur um
das Zeug auf dem höchsten Level auszulösen. Keine Corner cases, etc.
Und wenn ich dann ein Gefühl dafür habe, wohin die Reise geht, was ich
will und dass die Idee, die ich da ausformuliert habe gut ist, sodass
jetzt der Feinschliff kommen kann, dann fange ich an top down die Tests
zu schreiben, um a) die API zu fixieren, b) vergessene corner cases zu
entdecken und c) sicher zu gehen, dass ein späterer Bugfix kein anderes,
erwartetes Verhalten bricht.
> Wenn das API sich zu stark ändert,
> schmeisse ich die entsprechenden Tests lieber weg anstatt zu
> refaktorieren und schreibe neue.
Ich fand heute diesen Talk hier relativ interessant (okay, ich bin
schuldig mir sowas auf nem Sonntag anzuschauen, weil es interessanter
ist das das TV-Programm). Zufällig drüber gestolpert. Ich war
überrascht, dass der Abschnitt von Minute 15 bis Minute 28 "Spike and
Stabilize" meiner Art Software zu entwickeln sehr nahe kommt:
https://www.youtube.com/watch?v=USc-yLHXNUg
Gruß,
-Wanja-
--
..Alesi's problem was that the back of the car was jumping up and down
dangerously - and I can assure you from having been teammate to
Jean Alesi and knowing what kind of cars that he can pull up with,
when Jean Alesi says that a car is dangerous - it is. [Jonathan Palmer]
Back to de.comp.lang.java | Previous | Next — Previous in thread | Next in thread | Find similar
Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-07 21:19 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Peter <peter@localhost.com> - 2016-07-07 22:37 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Michael Paap <feunews@mpaap.de> - 2016-07-07 23:21 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-08 14:09 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Wanja Gayk <brixomatic@yahoo.com> - 2016-07-08 22:10 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Patrick Roemer <sangamon@netcologne.de> - 2016-07-09 00:17 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Wanja Gayk <brixomatic@yahoo.com> - 2016-07-18 00:33 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-18 01:01 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Patrick Roemer <sangamon@netcologne.de> - 2016-07-19 10:58 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Wanja Gayk <brixomatic@yahoo.com> - 2016-07-21 00:07 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-19 14:09 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Patrick Roemer <sangamon@netcologne.de> - 2016-07-08 00:28 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-08 14:13 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-08 16:05 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Wanja Gayk <brixomatic@yahoo.com> - 2016-07-08 22:35 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Patrick Roemer <sangamon@netcologne.de> - 2016-07-09 00:01 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-11 00:40 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-15 23:25 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-15 00:12 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle Wanja Gayk <brixomatic@yahoo.com> - 2016-07-08 21:57 +0200
Re: Unit-Tests von Einheiten ohne öffentliche Leseschnittstelle "Christian H. Kuhn" <qno-news@qno.de> - 2016-07-11 01:13 +0200
csiph-web