4D Developer Award 2016


In diesem Jahr wurde der Developer Award zum zweiten Mal verliehen. Zur 4D DevCon 2014 gewann ihn Markus Weber, Kollege aus der 4Dwerkstatt. In diesem Jahr hat den Anwesenden mein Beitrag Current4DTechnology am besten gefallen. Das freut mich sehr.

Eching 10.5.2016
Eching 10.5.2016

Den Beitrag habe ich online gestellt:



This year for the second time 4D Deutschland organised the 4D Developer Award contest. My 4Dwerkstatt-colleague Markus Weber won the 4D DevCon 2014 award. This year my contribution got most of votes from 4D developers. I’m pleased.

See here the english version and/or the original one in the german section.

Current4DTechnology (english) from Ortwin Zillgen on Vimeo.

Automatisches Testen

MarioS

Ein Gastbeitrag von Mario Schulz

Meine Situation unterschiedet sich nicht von der anderer 4D-Entwickler.

Kaum habe ich ein Modul fertig, schon kommen die nächsten Ideen. Dies könnte man noch einflechten oder jenes oder zu einem fertigen Modul möchte ein Kunde eine Erweiterung haben. Soweit ist das kein Problem. Dann geht es ans Testen. Die meisten Fehler sind schon dadurch gefunden, daß man sich sein neues Interface anschaut und einmal durchklickt, ohne auf Werte zu achten. 4D meldet die Laufzeitfehler von allein. Der Rest ist dann akribisches Nachrechnen, Ausprobieren und Testlisten abarbeiten. Ein Problem sind die Seiteneffekte. Diese tauchen dort auf, wo man sie nicht erwartet und werden übersehen. Meine Anwendung ist groß. Diese komplett von A bis O zu testen, ist alleine kaum zu schaffen.

Andere Sprachen sind in diesem Thema bereits weiter. Das weckt in mir (teilweise) Begehrlichkeiten. 4D ist nicht das Problem, sondern die monolithischen Architekturen, die mit derlei Sprachfamilien geschaffen werden. Wie sollen diese automatisch getestet werden, wenn in einer Objektmethode die gesamte Logik von Eventhandling, Geschäftslogik und Datenbankzugriff steckt.

Für das Testen lassen sich drei Bereiche unterscheiden.

1) Das Interace

Die GUI lässt sich von allen Bereichen am schwersten automatisch testen. So gibt es etliche Frameworks/Programme die einem das abnehmen. Die Natur der Frameworks/Programme ist ziemlich identisch. Sie feuern eine Sequenz von Events ab (vornehmlich Mausklicks), immer an der vordefinierten Position. Ziehen dann von einem Bereich ein Bildschirmfoto und vergleichen das mit einem hinterlegten Bild oder versuchen mittels OCR einen Text einzulesen. Bei einigen lässt sich noch eine Art delta hinterlegen, eine Abweichung die nicht bemängelt wird.

Alles in allem sehr aufwendig. Das Interface in meinen Anwendungen ist der Bereich, der sich am häufigsten und schnellsten ändert. Apple liefert alle ein bis anderthalb Jahre ein neues Interface und Windows zieht ebenfalls an.
Anschließend alle Tests anzupassen kann schnell in mehr Arbeit ausarten als eine eigene Testliste abzuarbeiten.

2) Funktionen

Ist der mit Abstand am Besten zu testende Bereich. Hierfür gibt es UnitTests. In Wakanda ist das YUI-Framework enthalten. Für fast jede Sprache gibt es mittlerweile ein xUnit-Framework. Für 4D hatte sich Mark Schaarke mal dran probiert: UnitTester for 4D v11 and v12.

Wie der Name bereits sagt, sind UnitTests für Units. In 4D gibt es keine Units. Vom Prinzip her hat es sich damit bereits erledigt. 4D verhindert aber nicht, das man sich über Präfixe Units schafft. Oder man sieht die Projektmethoden als Unit an, daran ist auch nichts falsch. Seitdem es Komponenten gibt, hat sich die Sache für mich geändert. In den Komponenten hab ich viel Funktionalität hinterlegt/ausgelagert
– Kommunikation mit diversen Servern
– Berechnung von Prüfziffern
– einlesen und parsen eines Dokumentes und dazugehörende Hilfsfunktionen.
Gleiches gilt für Methoden/Funktionen der HostDB, die noch nicht in Komponenten ausgelagert sind.

Bei Funktionen kann ich ein erwartetes Ergebnis mit dem Ergebnis vergleichen, den mir die Funktion liefert. Um diese zu überprüfen leg ich normalerweise ein Trace bzw. Breakpoint an die Stelle und überprüfe im Debugger, ob genau das Ergebnis kommt, das ich erwartet habe. Oder ich schreibe mir eine Dummy-Methode in der ich der Funktion die Testparameter fest übergebe, um mir dann die Ausgabe anzuschauen. Mit der Zeit sammeln sich diese Testmethoden an.

Kaum habe ich sie gelöscht muss ich sie anschließend neu schreiben, weil ich genau an dieser Funktion etwas ändern möchte. Ist alles in allem sehr zeitaufwändig. Also warum nicht die Testmethoden einmal schreiben und für den Test automatisch in die Host-DB eintragen und ausführen lassen. Mein Vorteil liegt darin, ich kann alle Tests auf einmal ausführen und erhalte nach wenigen Millisekunden das Ergebnis.

3) Datenbankzugriffe

Kann man ebenfalls mit UnitTests zugrunde rücken, setzen aber oft einen vordefinierten Zustand der Datenbank voraus. So kann ich hier auch die Konsistenz der Datenbank prüfen, also ob ein Feld in Abhängigkeit von einem oder zwei anderen Felder einen bestimmten Wert hat. Geht aber sehr schnell über in Tests die ich in einem Wartungsmodul erwarten würde. Wo der Kunde die Konsistenz seiner eigenen Datendatei überprüfen kann. Zum Beispiel haben alle Felder eine UUID zum synchronisieren und wenn nein dann aktualisiere den Datensatz. Brauch also nicht ich, sondern der Kunde/Support.

Schon eher wird für mich ein Schuh draus, wenn ich hier die hinterlegten Geschäftslogiken überprüfen kann. Ist in Tabelle y ein Datensatz vorhanden, wenn Methode z auf Tabelle x ausgeführt wird? Und wenn ja, haben bestimmte Felder die richtigen Werte?

Oder ich führe eine Aktualiserung der DB durch und will wissen, ob es funktioniert. Diese in die Tests aufzunehmen, macht meistens dann Sinn, wenn man erwarten kann, das durch einen Seiteneffekt – neues Betriebssystem, neue 4D Version – sich das Verhalten ändern kann.

Aber zurück zum Thema UnitTests.
Wer hier den heiligen Gral sucht, ist schnell enttäuscht. Aber einen Teil meiner Arbeit kann ich durchaus automatisieren bzw. vereinfachen.
– ich muss ein erwartetes Ergebnis mit einem Ergebnis vergleichen können, das ich nach Ausführen einer Methode/Funktion erwarte
– ich will den Testcode nicht in meiner Host-DB aufbewahren
– ich will es einfach haben: Komponente reinwerfen, starten, ausführen, Ergebnis sehen.

Komponente UnitTests

Die Komponente ist eine für 4D v14 aber alle Techniken gibt es bereits ab V13.
Zum Ausführen muss eine Callback-Methode hinterlegt werden. Selber anlegen brauch man sie nicht, das macht die Komponente. In der Callback-Methode wird der Testcode geladen (METHOD SET CODE), ausgeführt (EXECUT METHODE) und anschließend die angelegte Methode wieder gelehrt. Das Löschen einer Methode wird von 4D nicht unterstützt.

Ein anders Manko: hat man die Callback-Methode über den Explorer manuell geöffnet, ist sie schreibgeschützt und kann nicht für die Komponente verwendet werden. Damit die Komponente aber nicht nach dem Compilieren mit der Host-DB verknüpft ist, wird die Callback-Methode gelehrt. Ich brauche diese zum Testen nicht zum Ausliefern.

Um die Komponente zu starten reicht es, über Start/Methode ausführen „UnitTest_interface“ zu wählen. Man wird nach einem Arbeitsverzeichnis gefragt, hier werden alle Testsuites samt Tests gespeichert. Eine Testsuite zum importieren und Ausführen liegt der Beispiel-DB bei.

test_Suite

Wollen Sie eigene UnitTests anlegen, brauchen Sie eine Anleitung. In der Beispiel-Anwendung werden Sie beim Start gefragt, ob Sie das Tutorial sehen wollen. Machen Sie das.

UnitTestTutorial

 

Vorher laden Sie sich die  Testanwendung. Die Komponente entnehmen Sie der Testanwendung oder laden sie hier UnitTest-component.

Benutzen so wie ist für jedermensch, Source-Code auf Nachfrage.

DBZ_SIGNWIDGET

Signieren lassen

Kommt ein Paket an, hält mir der Auslieferer sein Gerät vor die Nase und bittet mich mit einem Stift auf diesem Gerät zu unterschreiben. x-mal gemacht und die Unterschrift ist mehr oder weniger die meine.

Kann ich das auch in 4D haben? Yep – hier ein Screenshot.
DBZ_SignWidget
… mehr