tag:blogger.com,1999:blog-7017123333978978050.post1751408644618099621..comments2022-04-01T05:15:14.655+01:00Comments on Rüdiger Plantiko: Refactoring in ABAPRüdiger Plantikohttp://www.blogger.com/profile/02393666282077884370noreply@blogger.comBlogger7125tag:blogger.com,1999:blog-7017123333978978050.post-29035311683815975212011-06-10T10:31:57.648+01:002011-06-10T10:31:57.648+01:00Sehr gut. Das heißt, dass meine Überlegungen nicht...Sehr gut. Das heißt, dass meine Überlegungen nicht völlig Praxisfern sind. Danke für deine AntwortenDavidhttps://www.blogger.com/profile/03208608344348558593noreply@blogger.comtag:blogger.com,1999:blog-7017123333978978050.post-8884376543663453582011-06-09T21:29:22.573+01:002011-06-09T21:29:22.573+01:00Aha, also eine Objektfabrik. Genau in der von Dir ...Aha, also eine Objektfabrik. Genau in der von Dir beschriebenen Form nutzen wir bei der Migros auch so etwas. Allerdings zu anderen Zwecken. Nicht um produktive DB-Klassen durch Teststubs zu ersetzen, sondern um nach Quertransport einer Klasse in ein anderes SAP-System mit Hilfe einer passenden Subklasse kleine Änderungen anbringen zu können. <br />(Das Verfahren habe ich auch im BSP-Praxisbuch beschrieben, Kapitel 3.5.5.3)Rüdiger Plantikohttps://www.blogger.com/profile/02393666282077884370noreply@blogger.comtag:blogger.com,1999:blog-7017123333978978050.post-55940474821964859622011-06-09T21:24:05.341+01:002011-06-09T21:24:05.341+01:00Hey,
Danke für die schnelle Antwort. Dependency In...Hey,<br />Danke für die schnelle Antwort. Dependency Injection ist auch für mich das Stichwort, wobei ich dabei den Weg gegangen bin, in einer Datenbanktabelle Interfaces und ihre Implementierungen zu hinterlegen. Durch den Einsatz einer extra Klasse, die sich um das Erstellen der konkreten Objekte kümmert, habe ich die Instanziierung völlig ausgelagert und kann diese dann dort beeinflussen<br />(z.B. Ein Flag setzen, dass die Testimplementierungen benutzt werden sollen)Davidhttps://www.blogger.com/profile/03208608344348558593noreply@blogger.comtag:blogger.com,1999:blog-7017123333978978050.post-19686191352416653112011-06-09T16:40:16.619+01:002011-06-09T16:40:16.619+01:00Und noch eine Ergänzung.
Auf
http://wiki.sdn.s...Und noch eine Ergänzung. <br /><br />Auf <br /><br />http://wiki.sdn.sap.com/wiki/display/ABAP/ABAP+Unit+Best+Practices<br /><br />habe ich einige praktische Tips zum Thema Modultests gesammelt. Ein Blick hinein könnte sich lohnen...Rüdiger Plantikohttps://www.blogger.com/profile/02393666282077884370noreply@blogger.comtag:blogger.com,1999:blog-7017123333978978050.post-22030417080118409282011-06-09T14:49:03.485+01:002011-06-09T14:49:03.485+01:00Zur Option 1 ist noch zu ergänzen, dass der Import...Zur Option 1 ist noch zu ergänzen, dass der Importparameter <b>io_db</b> vom Typ <b>ref to object</b> deklariert werden muss, nicht etwa <b>ref to lcl_db</b>, da ja die Klasse <b>lcl_db</b> nach aussen nicht bekannt ist. Wird ein Objekt übergeben, so muss es mit dem Casting-Move übergeben werden - vereinfacht könnte der Code etwa so aussehen:<br /><br />method constructor.<br />...<br />if io_db is bound.<br /> go_db ?= io_db.<br />else.<br /> create object go_db.<br />endif.<br />...<br />endmethod.Rüdiger Plantikohttps://www.blogger.com/profile/02393666282077884370noreply@blogger.comtag:blogger.com,1999:blog-7017123333978978050.post-61684381774682684302011-06-09T14:41:32.609+01:002011-06-09T14:41:32.609+01:00Hallo David,
ich habe keinen coolen Trick dafür, ...Hallo David,<br /><br />ich habe keinen coolen Trick dafür, den dann keiner versteht... <br /><br />Ich mache es so, wie Du es wahrscheinlich erwartet hast: <br /><br />Ausgangslage: Die zu testende Klasse hat ein privates Attribut <b>go_db</b> vom Typ <b>ref to lcl_db</b>, wobei in <b>lcl_db</b> die Datenbankzugriffe programmiert sind. Im Konstruktor der zu testenden Klasse wird "normalerweise" eine Instanz von <b>lcl_db</b> in das Attribut <b>go_db</b> gestellt. "Normalerweise" heisst: im normalen, produktiven Einsatz der Klasse.<br /><br />Beim <i>Testen</i> stelle ich in dieses Attribut <b>go_db</b> eine Instanz einer Subklasse <b>lcl_db_stub</b> hinein, die anstelle von Datenbankzugriffen z.B. auf internen Tabellen operiert.<br /><br />Das mache ich in der dafür vorgesehenen Setup-Methode der Unittestklasse, die ja vor jedem Testfall durchlaufen wird. Die Setup-Methode ist die Methode, in der ich auch die Instanz des zu testenden Objekts erzeuge.<br /><br />Wie bekomme ich die Instanz da hinein? Es gibt wohl drei Möglichkeiten, aber nur die erste ist wirklich gut:<br /><br />1. <i>Dependency Injection</i><br />Der Konstruktor der zu testenden Klasse bekommt eine optionalen Importparameter <b>io_db</b>. Wird dieser beim Aufruf versorgt, so wird sein Wert in <b>go_db</b> gesetzt. Wird er nicht mitgegeben, so wird im Konstruktor der zu testenden Klasse eine Instanz von <b>lcl_db</b> erzeugt. <br /><br />2. <i>Sich zum lokalen Freund machen.</i><br />Mit dem Konstrukt <b>class zcl... definition local friends lcl_...</b> erlaube ich der lokalen Testklasse, auf das private Attribut <b>go_db</b> zuzugreifen und den Stub dort hineinzustellen. Das ist eher schlecht. Denn im Konstruktor der zu testenden Klasse wird ja <i>doch</i> bereits ein Exemplar von <b>lcl_db</b> erzeugt - auch wenn es danach durch die Neuzuweisung von <b>go_db</b> der Garbage Collection anheimfällt. Wenn der Konstruktor von <b>lcl_db</b> z.B. bereits Datenbankzugriffe enthält, werden diese auch im Test ausgeführt. Das ist aber gerade das, was wir <i>nicht</i> wollen.<br /><br />3. <i>Das Attribut <b>go_db</b> wird öffentlich gemacht</i> <br />und kann so von aussen nach Instanzbeschaffung noch auf den Stub umgesetzt werden. Nicht gut, weil obendrein auch noch ein Internum der Klasse veröffentlicht wird: Insbesondere muss <b>lcl_db</b> dann einen geeigneten öffentlichen Typ haben, lokale Klassendefinition allein reicht dann nicht. Noch ein Nachteil.Rüdiger Plantikohttps://www.blogger.com/profile/02393666282077884370noreply@blogger.comtag:blogger.com,1999:blog-7017123333978978050.post-45742742269150564872011-06-09T12:26:13.871+01:002011-06-09T12:26:13.871+01:00Hi Rüdiger,
ist ja jetzt schon drei Jahre her, das...Hi Rüdiger,<br />ist ja jetzt schon drei Jahre her, dass du den Artikel geschrieben hast. Aber vielleicht klappts ja trotzdem.<br /><br />Du schreibst davon, dass du die Datenbankaufrufe in lokale Klassen verlagerst, um sie für das Testen durch Stubs austauschen zu können.<br /><br />Wie teilst du deiner eigentlichen Klasse mit, ob sie nun den Stub, oder die eigentliche lokale Klasse benutzen soll?<br /><br />Machst du das manuell im Quellcode vor dem Test, oder hast du dir da eine coole Methode überlegt, wie das automatisch stattfinden kann?Davidhttps://www.blogger.com/profile/03208608344348558593noreply@blogger.com