Nun habe ich ihn in den letzten Einheiten vorgestellt,
wie dieses Verhalten passieren soll, Refactoring durchzuführen,
bei Legacy-Systemen, die nicht so eine gute Modularität aufweisen,
die starke Kopplungen verweisen, die nicht so digitalile Tests haben,
dass wir dem Entwickler die Sicherheit geben,
den Mut geben, dass Sicherheitsnetz aufspannen,
dass er den Mut haben kann,
tatsächlich hier Refactorings durchzuführen und wie führen wir solche Tests durch,
wie entkoppeln wir das,
Ich denke, das ist zu viel des Guten nun müssen wir,
bekommt, wird es Zeit, ein bisschen Kritik zu üben.
Lassen Sie uns zunächst erst mal kritisieren,
was an diesem Fake-Objekt denn dran war. Ja,
also wir hatten, ich gehe mal noch mal dahin,
dieses Fake-Objekt stellt denn hier dieses, steht so ein Display da.
Ja, und ist die Frage,
ist denn das Fake-Objekt wirklich für den Test geeignet?
Was testet es denn? Testet es,
ob der Richter das Richtige angezeigt wird
Teilweise. Es testet nicht, ob die Elektronik die Signale
richtig verarbeitet. Ob die Bildpicken-Punkte-Punkte richtig angesteuert werden. Ob
das Display überhaupt geht, das geht nicht. Das Einzige,
was das testet, ist die Datenverarbeitung, die vorher passiert.
Was passiert mit dem Scancode? Wird der richtig an die Datenbank
übertragen? Wird aus der Artikeldatenbank der richtige Wert geliefert?
Wird der Wert bis hierher übergibt? Was die Elektronik
damit macht, ist vom Test jetzt nicht betroffen.
Also das ist hier von dem Fake-Display nicht betroffen.
Wenn wir die Elektronik testen wollen, müssten wir
anders vorgehen
Und auch soweit kein Problem. Das könnten wir durchaus tun
. Es ist Tests sind durchaus selektiv.
Ich schreibe das mal kurz auf
Die CIS-Objekt testet ja, ist das die Anzeige?
Ist das jetzt die Datenverarbeitung, die Datenbereitstellung?
Nun die Elektronik ist dabei nicht getestet, also die Elektronik,
ob die da in jeder Buchstabe dann richtig auf dem Display landet,
ob die Punkte richtig angesteuert werden,
ob es alle Punkte mitleuchten oder sowas.
Das müsste man noch separat testen. Das ist aber
völlig okay aus der Sicht. Wir könnten noch sagen,
ja, es enthält alle Methoden aller relevanten Methoden des Originals
Das können wir uns noch mal kurz ein Beispiel anschauen.
Ja, also diese Methode Showline,
die beim Original haben, die gibt es auch.
Zusätzlich gibt es noch Dinge, die wir brauchen,
um die Beobachtbarkeit sicherzustellen
Soweit zu dem Fake-Objekt. Eine weitere Kritik,
die wir anbringen müssten, ist zu den Fragen der Trennung.
Nämlich, dass wir jetzt mit geändertem Kot arbeiten.
Wie sieht denn das aus? Wir führen tatsächlich
eine Kotänderung durch
Was ist Test überhaupt? Test kann ja sowieso nicht die vollständige, richtige Funktion darstellen.
Test kann nur die Anwesenheit von Fehlern zeigen für bestimmte Fälle,
beziehungsweise wenn der Test fehlschlägt, deren Totest nichts zeigt,
deren Abwesenheit weg ein Test zeigt nicht den Beweis,
dass Quellcode tatsächlich fehlerhaft, fehlerfrei ist.
Das ist also eigentlich nicht viel mehr als eine vertrauensbildende Maßnahme.
Und wenn wir jetzt noch den Test nicht mit im Code machen,
wie es wirklich ist, sondern irgendwie Teile, das kurz sind,
ausgetauscht, nämlich das, was wir genau haben.
Ja, wir haben ja nicht das richtige Display,
sorry, das sollte wieder, das solltet ihr nicht stehen.
Sollte nur ein Punkt sein. Wir haben nicht das richtige
Display, sondern wir haben ja hier nur etwas anderes.
Ist, da kann man so einem Code überhaupt noch vertrauen.
Kann man so einem Test überhaupt vertrauen?
Hilft der Test uns überhaupt? Das ist hier tatsächlich
die große Frage
Musik Das zeigt sich zum Beispiel daran, ich weiß nicht,
wer von Ihnen schon solche Erfahrungen gemacht hat,
dass es bei Entwicklern ganz schlecht angesehen wird,
wenn man über Compiler-Schalter oder über irgendwas andere Maßnahmen Code austauscht,
der dann getestet für einen Test anderen Code hat,
als für die Realität.
Dann kann man sagen, okay,
das getestete System hat die Fehler nicht,
aber wissen wir denn, ob ich das reale System habe?
Wir wollen, um das zu erreichen, sollte die Art,
die Menge der Kultänderungen und die Ansatzstellen der Kultänderung soll minimiert werden.
Gut, Änderungen Nur außerhalb der Kurt-Basis.
Und wir sollten klar,
verständliche Austauschmechanismen haben
Ich möchte das hier mit Rot noch mal reinschreiben.
Cool sollten wir halt zum Test nicht verändern.
Das ist ein ganz wesentlicher Punkt, um das Vertrauen in
sowas zu erhalten. Diese Mechanismus des Code-Änderns Hier,
den wir hier mit diesem Interface haben, zum Einführen eines solchen Mock-Objekts,
sollten wir also nicht einfach im Code irgendwo was ändern,
sondern wir sollten dafür Mechanismen haben.
Und diese Mechanismen möchte ich hier Ihnen unter dem Namen Sieben vorstellen.
Die Frage dazu hatten wir hier eben schon stehen irgendwo.
Genau. Frage 21,
erläutern Sie das Konzept des Teams und wie wirken die Brettprozessor links,
Link und Objekt Teams,
also die Frage
Drei Fragen. Lassen Sie uns zu dem Punkt kommen,
was sind solche Siems? Häufig ist es so, dass wir,
hier steht nochmal die, dieser Punkt, den wir eben schon hatten,
bei Test und Einsatz sollte der Code sich entsprechen, aber wir brauchen die Entkopplung.
Umso mehr brauchen wir die Entkopplung,
als wir dann beim Testen häufig merken, ja okay,
fachlich sind das irgendwelche Module, aber Entkopplung ist nicht so,
dass Abhängigkeit minimiert werden und das Siemen, was wir Michael Feathers in seinem Buch einführt, Auf Deutsch würde man sagen,
Saum, wer von ihnen schon mal genäht hat, weiß,
Saum ist die Stelle, wo man den Stoff zusammenfasst,
wo man also auch leicht wieder trennen kann,
eine Naht, das ist hier in unserer Methodik,
die Stelle im Code, wo man das Verhalten ändern kann,
ohne wirklich etwas zu zerstören, ohne den Code wirklich zu bearbeiten,
ich sag mal, an dieser Stelle.
Und wir wollen das so erreichen, dass wir die Mechanismen,
die die Programmiersprachen und die Entwicklungsumgebung uns bietet,
dazu nutzen, zu dieser Veränderung zu kommen,
ohne dass wir wirklich den Code von Hand
jedenfalls ändern
Ja, also hier zum Beispiel durch Polomorphie könnten wir da sowas machen.
Und die Stelle, wo wir dieses Verhändeln einschalten,
soll dann irgendwie außerhalb sein. Und das ist das,
was Feathers als Lieblingspoint, wir können es als Aktivierungspunkt übersetzen,
bezeichnet, nämlich dort, wo wir wirklich die Umschaltung vornehmen.
Ja, und für diese Polomorphie wäre die Instanzierung das Ganze.
Ich möchte, dass einem Beispiel vorstellen.
Dieses Beispiel bedient, benutzt Techniken der Objektorientierten Programmierung.
Deswegen heißt das Ganze auch Objekt-Teams. Wir werden dann noch
zu Link und Pre-Prozessor 7
Basis, technologische Basis für Objekt-Teams ist das dynamische Binden, ist die Polymorphie. Beim dynamischen Binden zur Erinnerung für diejenigen unter ihnen,
die sich nicht mehr so ganz genau daran erinnern,
ging es darum, dass zur Laufzeit andere Klassen,
die Objekte anderer Klassen möglich sind,
weil ich nämlich insbesondere spezialisierte Klassen habe,
also zum Beispiel kenne ich Unterklasse von dieser Klasse,
Zelle hier verwenden, um dann zu sagen,
welche Methode soll wirklich ausgeführt werden in diesem Fall,
existiert gar keine weil es eine abstrakte Klasse ist.
Ist das so gedacht, dass hiervon gar kein Exemplar existieren?
Zur Laufzeit ist es entweder die Exemplar dieser Klasse oder ein Exemplar dieser Klasse.
Das wird bestimmt dadurch, welche Klasse das Objekt dann wirklich hat.
Und diese dynamische Binden ist etwas, was wir uns hier zur Null zu machen.
Und das dynamische Binden über die Steuerung passiert zum Instanzierungszeitpunkt.
Also dann, wenn wir ein Objekt erzeugen und initialisieren.
Wir schauen uns das jetzt mal an. Wir haben hier eine Klasse,
Beispiel im Java, wo wir ein Spreadsheet benutzen,
also sie können auch Sachen Excel, wenn sie wollen,
die Absammelbegriffe, zusammen mit Bezeichnung ist.
Spreadsheet und wir haben in den Spreadsheets,
ist das berechnen die wesentliche, die wesentliche Aktion,
die man da macht und wir wollen gerne dieses Rekergulate ersetzen
durch etwas anderes, was dann abgetrennt ist.
Im oberen Teil der Folie haben wir das erstmal in der Form dargestellt,
ohne sie, also ihr wäre es so,
wenn ich das Rekergulate durch was anderes ersetzen möchte,
zum Beispiel durch ein Fake-Objekt
Dann müsste ich ein anderes Cell haben. Das Cell wird
aber hier aus Formularsau mit einer bestimmten Initialisierung gebildet.
Das heißt, ich müsste den Code hier verändern.
So eine Codeveränderung ist nicht erwünscht, weil sich das Vertrauen verringert.
Wir würden, könnten es aber so machen,
dass wir jetzt das irgendwo an einer anderen Stelle machen.
Diese andere Stelle könnte es sein,
wo von außen her das aufgerufen wird, dass wir einen anderen Aufruf haben,
indem wir zum Beispiel hier einen anderen Parameter übergeben.
Hier war es Parameter los und die Initialisierung,
Instanzierung passierte hier innen drin. Und hier können wir statt
die Instanzierung innen drin in der Methode zu machen,
können wir das als Parameter übergeben, die Zelle.
Und dann können wir steuern, welche Zelle das ist,
dann können wir steuern, dass es zum Beispiel hier eine andere,
eine Fake-Zell oder was auch immer ist.
Ja, und dem wird, die können wir dann übergeben.
Und dann wissen wir, das, was dann aufgerufen wird,
ist, dass Fake-Sell, das Kalkulat von Fake-Sell.
Und damit wäre, dass der sie, ja.
Was erreichen wir damit? Wir erreichen hier den Aufruf,
den Austausch einer anderen Methode, den Austausch bezüglich da ist des Aufrufs.
Und dadurch passiert eine andere Methode,
wird aufgerufen
Der zu testende Code bleibt unverändert. Wir haben es
nur ausgelagert und wir müssen natürlich irgendwo das steuern.
Und das wäre der Zeitpunkt der Instanzierung, der hier außerhalb liegt.
Wir berufen das mit einem schon bereits instanzierten Exemplar von Zelle auf.
Ich finde es ja auch und übergeben das und können es damit durchführen.
Soweit ein Java-Beispiel. Wir haben auch noch hier in der Folie
ein kleines C-Plus-Plus-Beispiel für diejenigen unter ihnen, die die C-Plus kennen.
Sie können dann hier sehen,
dass es hier eine globale Methode gibt für den die uns,
die zum Testen, in dem Fall Gegenstand unseres Tests sein sollen,
beziehungsweise diesen Test beeinträchtigt.
Wir möchten gerne für den Test diese globale Methode loswerden.
Das könnten wir natürlich machen, indem wir sie ersetzen,
rausstreichen, wie auch immer. Das wäre aber wieder
so eine Code-Veränderung, die wir sie nicht nicht wollen.
Die nächste Folie verrät uns, wie wir den Aufruf hinbekommen können.
Hier können wir eine virtuelle Methode mit gleicher Signatur einfügen.
Das wäre jetzt das hier oben
Ja, diesen, ich gehe mal wieder zurück,
der Post-Receiver-Error wäre jetzt hier. Also wir haben die Methode
mit der gleichen Signatur, die fügen wir hier ein.
Und dann haben wir hier die Möglichkeit, mit dem gleichen,
mit dem gleichen Buddy etwas zu haben, was überschreibt.
Ja, also wir unterschreiben hier die Unterklasse in der Unterklasse,
die Methode, die wir eigentlich austauschen wollen.
Und damit können wir testen, ohne dass wir die
eigentliche Klasse beeinträchtigt. Ja, der Test ist möglich,
ohne dem Effekte rufen wir wirklich nicht eine andere Klasse auf
Es ist Holymorphie im gleichen Zeitpunkt, der zu testen gekohlt wird,
nicht verändert und genauso wie eben Java-Beispiel haben wir Handelssissier um
die Inzension wieder eines anderen Exemplars oder eines Essenbars einer anderen Unterklasse.
Wir haben die Möglichkeit, diese,
vielleicht sollten wir noch soweit sagen, die Objekt-Teams sind,
wie geht es los hier mit den Object-Teams,
das sind die am häufigsten verwendeten Siems in Objekte und Typensprachen.
Sie nutzen das Konzept des dynamischen Bindens,
Sie sind für viele Zwecke inobjektuentierten Programmierung eine gute Lösung
Die weiteren, zweiten weiteren Formen, die ich Ihnen jetzt vorstelle,
Pre-Prozessor 7 und 7s und links Teams,
sind eher Spezialfälle, die wir hier nicht so direkt brauchen.
Sie sind von der Übersichtlichkeit her ein bisschen weniger gut. Ja,
hier ist es so, dass wir ganz klar die Oberklasse,
also wir hatten ja jetzt zwei Beispiele,
die Oberklasse unverändert lassen,
nur eine abgeleitete Klasse bilden,
sei es nun hier als Instanz eines Interfaces oder als andere Klasse,
die ich für den Test dann nutzen kann,
und früher
der Abstausch zum Zeitpunkt der Instanzierung passiert
Jetzt, wie gerade besprochen, zum Pre-Prozessor C. Es gibt Programmiersprachen mit C plus Plus,
die für die ein Pre-Prozessor, die erste Verarbeitung,
den ersten Verarbeitungsschritt der Programme, das Quellcodes vornimmt,
der wird es vor allen Dingen genutzt, um Makros zu benutzen.
Diese Makros sind gerade bei C plus Plus,
machen sie überhaupt nur die Objektorientierung,
weil dahinter liegen die dazwischen danach erzeugte Sprache C.,
kennt das Konzept der Klasse und des Objekts und der Kapsel und nicht der Pre-Prozessor macht das alles.
Im Produkt Drehprozessor können wir zum Beispiel nutzen per Makrodefinitionen um Kotersetzungen zu machen.
Ja, also wir können es zum Beispiel so machen,
dass wir mit der Define-Anweisung den Code ersetzen machen können.
Und dann können wir eben auch dieser Code-Austausch,
den Gut-Austausch machen, Parameter, Rückgabewerte umlenken von Aufrufen.
All das könnten wir mit Define machen. Und das wäre
die eine Möglichkeit und die andere Möglichkeit per Include,
geänderten Code einbinden, dass er an einer bestimmten Stelle dann wirksam wird,
wie er im Original nicht ist.
Ja, dieses Einbinden führt dazu,
dass wir den Code mit Abhängigkeiten Ersetzen durch etwas anderes,
nämlich zum Beispiel durch ein Fake- oder Morkobjekt,
das ist dieser Aspekt des Trennens und wir können den gut um Überwachungs- und Beobachtungseineinweisung ergänzen,
dass wir das überwachen zum Zweck des Testes.
Der Zeit, der Punkt, wo wir sowas durchführen,
wo wir das starten, sind Pre-Prozessor-Einweisungen.
Ich möchte Ihnen das kurz am Beispiel zeigen. Wir haben hier eine Bibliotheksroutine,
die wir, die DB-Update heißt, die etwas ausführt,
um aus der Datenbank neue Inhalte auszuführen. Diese Bibliotheksroutine erfordert,
so hatten wir es vorher schon mal gesagt, ja,
etwas, was vom Aufwand her über ein Unities hinausgeht,
nämlich den Zugriff auf eine Datenbank.
Für die Beobachtung wäre es jetzt notwendig, etwas anderes hier
stattdessen einzusetzen und das würden wir jetzt machen, indem wir die Header-Datei verändern. Ja,
wir haben hier eine andere Datei, die wir einbinden,
wenn etwas, wenn wir den Test durchführen, ja,
also zum Beispiel, wenn jetzt der Schalter,
das Makro ein paar Meter Testing definiert wird und darüber könnten wir jetzt etwas anderes hier einfügen.
Zum Beispiel hier eine solche Anweisung, dass wir die letzten Ausgabe wert speichern.
Das wäre letztlich so etwas, was wir zu beobachten auch
durchführen können. Die Abtrennung wäre jetzt der Austausch,
dass wir eine Steueranweisung, die das Umstellen ermöglicht und das,
was wir austauschen, wäre jetzt hier ein ganz anderer Code
Diese Art der Programmierung steht ein bisschen in Kritik,
muss ich sagen, sehr in der Kritik, insbesondere dafür,
für testen, weil wir ja tatsächlich den Code austauschen.
Wir ersetzen wirklich Quellcode durch eine ganz andere Anweisung.
Und das ist nicht sehr übersichtlich,
was passiert bei diesem Makro vielleicht noch irgendwo im Quellcode,
wenn wir hier einfach nur so einen Compiler-Schalter haben,
der doch mal cool austauscht, gibt das das vielleicht auch nochmal irgendwo.
Da müssen sie erst ausführlich suchen,
um da sicher zu sehen, dass das nicht passiert.
Deswegen haben diese solche Sachen mit Makros zu spielen,
um den Code auszutauschen, Zusammenhang mit Tests, ein ganz schlechtes Ansehen.
Man versucht, das zu vermeiden. Ich möchte es ihm
trotzdem vorgestellt haben, also auch der Pre-Prozessor bietet Möglichkeiten,
etwas für Trennung und Beobachtbarkeit zu tun.
Als letztes möchte ich Ihnen links Teams vorstellen. Auch hier
gibt es wieder eine ausgelagerte Stelle zum Austausch, nämlich,
wenn wir ihn hier den Linker bemüht, um Austausch vorzunehmen.
Der Linker, das ist das Teil im Programmablauf oder im Ablauf der Erzeugung eines ausführbaren Programms,
der symbolische Adressen mit realen Adressen verbindet,
und dabei Aufrufe zusammenbaut aus verschiedenen Paketen, die einzeln bereits kombiniert sind.
Ja, also wir haben einzeln kombinierte Pakete,
die wir per Import typischerweise einbinden. Und dieses Einbinden könnte
der Punkt sein, an dem ich einen Austausch vornehme.
Also statt dem originalen Paket, das steht in der originalen Klasse,
binde ich eine andere Klasse ein, die auch schon übersetzt ist.
Und die dann die Abhängigkeiten, die ich ausland, loswerden will, nicht aufweist.
Also dazu muss ich aber zunächst erstmal den Hut der irgendwelche
solche Abhängigkeiten hat, Nebeneffekte hat, in einem separaten Paket haben.
Ich muss also irgendwie Umstrukturen in den meisten Fällen.
Und dann tausche ich dieses Paket gegen ein anderes Paket aus,
was nur diese Beobachtbarkeit hat, wenn wir das vorhin mit dem Sales,
mit dem Display haben, müsste es zum Beispiel,
also diese Klasse, die das wirkliche Display hat,
die müsste dann auslagern, in einer anderen Klasse das ersetzen.
Und dann wird beim Linken eine andere Klasse hinzugenommen und die Originalklasse ist nicht mehr vorhanden.
Das ist tatsächlich auch eine Möglichkeit, eine Veränderung vorzunehmen.
Der Aktivierungspunkt wäre hier, Steuerung des Linkers, in welcher
Reihenfolge wem der Pakete mit sich. Diejenigen von ihnen,
die Java manchmal über die Kommandozeile benutzen, die wissen,
dass die Variable Class Pass, die Reihenfolge der Suche nach Paketen steuert.
Deswegen könnten wir hier, im Winter den Glas Pass verändern können,
wir sagen, okay,
nehmt erstmal ein anderes Paket und dann ist das das Paket mit
dem Fake-Objekt und dann wird das Fakebook-Bejekt eingezogen und danach kommt irgendwo in das reale Objekt,
in den Glas Pass hier,
das Paket mit dem realen Objekt und dann würde das geben.
Also der Austausch passiert, gestört über die Umgebungsvolgable
und was wird ausgetauscht, das Einbinden von anderen Klassen über
andere Pakete
In und ans Beispiel dafür. Wir wollen in einem Java-Programm Tabellen auswerten.
Das passiert mit der Klasse Pars und diese Klasse Pars,
die wollen wir hier, die wird hier zur Berechnung benutzt.
Und wir wollen jetzt diese Klasse Pars austauschen,
dass es ohne sie geht, dass wir sehen,
was passiert denn da. Das wäre die Möglichkeit wäre,
dass wir jetzt die Klasse Pars, die irgendwo herkommt,
nämlich in dem Fall aus dem Paket fit,
dass wir diese Klasse austauschen,
indem wir
das ganze Paket fit austauschen
Ja, und in dem Fall würde bei New Pass
dann eine aus einem anderen Paket genommen.
Und das neue Paket, das Ersatzpaket mit dem Fake-Objekt statt Pass
, sollte natürlich genau die gleichen Klassen enthalten.
Und die Klassen sollten genau die gleichen Signaturen enthalten,
damit es hier wieder passt. Aber sie haben einen anderen Inhalt.
Und das Ganze wird gesteuert dadurch, dass wir im Klars Pass
das Paket fit aus einem anderen Direktory nehmen lassen.
Und das ist dann das Fake-Paket. Ja,
das Paket mit dem Fake-Objekt. Und dann wird die
über Import
was anderes eingebunden
Reihenfolge, wie eine Fit gesucht wird, dass dann ein anderes Ding gefunden wäre.
Zu guter Letzt möchte ich noch zu dem Beispiel zurückkommen,
was wir einfangs bei den Objekteams hatten.
Da hatten wir diesen Quellcode, wo wir hier diese globale Methode loswerden wollten.
Hatten wir schon mal als Objekteam gehabt. Also der Objekteam war,
dass wir eine virtuelle Mission um die Funktion aufrufen,
die die gleiche Signatur hat, die dann woanders implementiert ist.
Und das wäre über dynamisches Binden erreichbar. Man könnte das Gleiche auch in der Sprache Ziel plus über ein Linksieben machen,
in dem wir ein anderes Paket einbinden, in andere Bibliothek,
mit dem Stubb, mit anderer Einbindung, das wäre eine Veränderung,
da gibt es ja nicht den Classpas,
aber ihr könnt mir über das Make-File das steuern,
woher werden die Pakete geholt, die Klassen.
Man könnte das genauso gut als Pre-Prozessor 7 realisieren,
indem wir ein Makro haben,
was dieses Post-Receive-Error neu definiert und damit einen anderen Aufruf an diese Stelle setzt.
Durch eine wirkliche Code-Veränderung, ja, und da wäre,
dass wir ein Compiler-Schalter haben, der eben Pre-Prozessor steuert, wie alles denken.
Wir unempörten uns das aber dann aufrufen, so wie vorhin
das durch die feine Testing. Lass noch mal so Gegenüberstellung,
es sind verschiedene Formen von diesen Themes möglich und das Wesentliche an den Themes ist,
dass wir es trennen, dass wir die Trennung vornehmen,
der zu testende Code bleibt unverändert.
Alles, was wir an Veränderungen haben, machen wir außerhalb.
Wir rufen damit nur den Code auf mit Make-afake oder Mock-Objekten
in eine Veränderung vorzunehmen