AW: [mailinglist] [Python-de] Funktion sucht Aufrufer

robert kuzelj robert_kuzelj at yahoo.com
Fre Sep 10 20:26:04 CEST 2004


>>gerne genommes konstrukt zb. in aspekt orientierten sprachen
>>(cflow | cflowbelow). warum? eine program laeuft im testmodus
>>und deine funktion "getFoo(): return Foo()" moechte in dem
>>falle lieber ein neues TestFoo() zurueckgeben (protokoll
>>gleich zu Foo).
>>die einzige moeglichkeit das anders hinzubekommen waere das
>>objekt, dass getFoo besitzt mit dem wissen ueber den "testzustand"
>>zu versehen. das kann auf zwei arten passieren per membervariable
>>oder als uebergabe variablen durch alle func/methoden aufrufe.
> Ich sehe da noch globale Variablen oder Factories, oder auch sehr nett: 
> konditionale imports.
ich glaube globale variablen diskutieren wir jetzt lieber nicht ;-)
Factories waere ne moeglichkeit; kann aber eventuell fuer die
aufgabe zu viel aufwand sein.

>>beide optionen moegen nicht immer zur verfuegung stehen. wenn objekte
>>zb. durch faktories erzeugt werden und es keine moeglichkt gibt
>>den zustand zu setzen. moeglichkeit zwei ist zudem enorm fragil.
> Gerade da geht das doch sehr gut: Der ganze Sinn einer Factory liegt doch eben 
> genau darin, eine protokollinvariante Implementation zu liefern - wenn das 
> nicht so waere, koennte man ja gleich eine konkrete Implementatiton liefern.
ah, ich seh, da hat jemand das gof-buch gut verinnerlicht. ;-)

der unterschied liegt darin, dass die irgendjemand (in dem fall der
TestCase) der Factory mitteilen muss, dass sie jetzt im testmode
arbeitet. also sowas aFooFactory.test_mode = TRUE.

zudem koennte es sein, dass man selbst im test modus nicht immer
ein TestFoo will. vieleicht moechte man ein "normales" Foo wenn
man im TestCase aufgerufen wird und sich im DatabaseManager befindet,
oder, oder, oder.

klar kann man dann aFooFactory.test_mode = FALSE setzen, wenn
man ein handelt auf die Factory hat. das sieht aber eventuell
merkwuerdig aus mitten in code, der ansonsten nix mit testen zu
tun hat.

>>def getFoo():
>>    if (suche_stack_nach_aufrufenden_testtreiber()):
>>       return TestFoo()
>>    else:
>>       return Foo()
> 
> 
> Also letztlich ist das ja nix anderes als eine Factory - und halt 
> parametisiert ueber den Stack. Auf die Idee bin ich noch nicht gekommen, aber 
> als ueberlegen kann ich das auch nicht wirklich empfinden. Man muss ja 
> jeweils gleich viel wissen - entweder eine Variable abfragen, oder wissen wie 
> der Stack auszusehen hat.
wissen muss ich in der tat beides. im falle von globalen variablen oder
factories muss ich aber konkret steuern was passiert. ich habe also den
test ueber verschieden stellen des codes gescattert. die sache mit den
stack hat den vorteil, dass ich genau an einer stelle eingreifen muss.

>><code achtung="unvollstaendig_nur_zur_demo">
>>def test_advise(Type):
>>    #wrap original funtion into delegate
>>    if (suche_stack_nach_aufrufenden_testtreiber()):
>>       return TestFoo()
>>    else:
>>       return delegate()
>>
>># und dann hier
>>@test_advise(TestFoo)
>>def getFoo():
>>       return Foo()
>></code>
>>
>>nicht nur, dass du in dem fall die testzustand nicht setzen musst,
>>dein eigentlicher code bleibt vom wissen um das testen voellig
>>unberuehrt und wartbar. ist doch nett.
> 
> 
> Wo ist da jetzt der Gewinn? Ich bin ja auch gespannt auf Dekoratoren, aber das 
> hier aendert nix - gleicher code, und eine Deklaration vor getFoo - wenn man 
> nicht weiss, was die wirklich tut, dann ist mir die obrige Variante lieber, 
> denn dann sehe ich direkt was wann passiert.
der punkt ist, dass ich davon eigentlich nix wissen will. stell dir
einfach vor getFoo wurde von nem fachprogrammierer gecoded und der
dekorator von nem tester (bloedes bsp. aber mir will auf die schnelle
kein anderes einfallen)

es geht halt nur drum den konkreten testcode (der ja hier voellig
trivial ist) vom produktionscode zu trennen. und das ist ein _riesiger_
vorteil.

> Du hast ja selber schon die aspekt-orientierung erwaehnt - ich halte das 
> durchaus auch fuer eine nette Idee, IMHO aber nur dann sinnvoll wenn die 
> Aspekte hinreichend unabhaengig sind. Beispiele sind zB tracking/logging, 
> Transaktionsmanagement, authentifiziernung/authorisierung, boxing/unboxing. 
das ist eine moeglichkeit - eine andere ist zum beispiel eben trennung
von prodcode und testcode. ich benutze aspectj ganz heftig dafuer
blackbox klassen aufzubohren. ich habe temporale daten, die ich in der
DB speichere und bei denen der server immer einen zeitstempel aufdrueckt
das kann vom aussen aufgrund von security aspekten nicht geaendert
werden. ich hefte deshalb an die objekte, die an den server gehen daten
drann und habe aspekte, die dann diese daten interpretieren und zb
dann andere zeitstempel erzeugen. ansonsten wuerden meine tests wochen
dauern

> In dem Moment  aber wo ein Aspekt soviel wissen muss ueber interna des Codes 
> an den er gebunden wird, sorgt er nur fuer unueberschtlichkeit - dann lieber 
> alles an einem Platz.
dem kann ich nicht zustimmen. wenn ich meine apis (ausschliesslich) fuer
  das testing aufbohren muss bin ich eher ungluecklich.

> Aber das ist nat. alles Ansichtsache, und die Idee scheint zumindest nicht 
> kraenker als andere :)
mir kam sie auch erst nach dem genuss mehrerer dosen red bull ;-)

ciao robertj