Devmate: Generierung von JUnit- Testfällen aus Java- Methodensignaturen

Größe: px
Ab Seite anzeigen:

Download "Devmate: Generierung von JUnit- Testfällen aus Java- Methodensignaturen"

Transkript

1 Eingereicht von Jakob Faschinger Angefertigt am Institute for System Software Devmate: Generierung von JUnit- Testfällen aus Java- Methodensignaturen Betreuer o.univ.-prof. Dr. Hanspeter Mössenböck April 2021 Masterarbeit zur Erlangung des akademischen Grades Diplom-Ingenieur im Masterstudium Computer Science JOHANNES KEPLER UNIVERSITÄT LINZ Altenbergerstraße Linz, Österreich DVR

2

3 Masterarbeit devmate: Generierung von JUnit-Testfällen aus Java- Methodensignaturen Student: Jakob Faschinger Betreuer: Prof. Hanspeter Mössenböck Beginn: 1. Juni 2020 o.univ.-prof. Dr. Hanspeter Mössenböck Institute for System Software T F hanspeter.moessenboeck@jku.at Secretary: Birgit Kranzl Ext 4341 birgit.kranzl@jku.at devmate ist ein Werkzeug für Softwareentwickler, mit den man schnell und einfach Unit-Tests generieren kann. Um dieses Ziel zu erreichen, werden Testentwicklungsverfahren wie Äquivalenzklassenanalyse oder Randwertanalyse verwendet. Das Testen einer Methode in devmate besteht aus folgenden Schritten: Anhand einer bestehenden Methodensignatur wird ein Skelett eines Testmodells erstellt. Dieses Modell kann der Tester um Äquivalenzklassen, Repräsentanten und Testfälle erweitern. Das erweiterte Testmodell kann in eine Unit-Test-Klasse überführt werden. Der beschriebene Prozess ist unabhängig von Programmiersprachen und Unit-Test-Frameworks. Jedoch muss devmate für jede Programmiersprache und für jedes Unit-Test-Framework erweitert werden. devmate unterstützt aktuell C# als Programmiersprache und NUnit als Unit-Test-Framework. Eine Erweiterung von devmate um Java und JUnit ist Ziel dieser Arbeit. devmate besteht aus folgenden 4 Komponenten: IDE+Parser. Diese Komponente ist in eine IDE integriert, extrahiert aus Methodensignaturen Informationen und übersetzt diese in ein sprachunabhängiges Modell (Public Language, oder kurz PL). Zusätzlich übernimmt diese Komponente die Koordination zwischen den Server-Komponenten. Test Generator. Hier sind die Testentwurfsverfahren (z. B. die Äquivalenzklassenanalyse) implementiert. Diese Komponente ist sprachunabhängig. Code-Generator. Diese Komponente generiert Test-Code für ein Unit-Test-Framework. Code-Merge. Ist für die Vereinigung verschiedener Test-Code Dateien verantwortlich. Daraus ergeben sich die inhaltlichen Schwerpunkte dieser Arbeit: Entwicklung eines Plugins für eine Java-IDE (TBD) im Rahmen des devmate Produkts, welches Informationen aus Methodensignaturen extrahieren kann. Entwicklung eines Generators, der aus dem devmate Testmodell JUnit-Code erstellt. Die Arbeit ist in regelmäßigen Abständen mit dem Betreuer sowie mit der Kontaktperson des Unternehmens zu besprechen. Ein Zeitplan mit Milestones ist innerhalb von 3 Wochen nach Beginn der Arbeit abzuliefern. Der Zeitplan soll im Laufe der Arbeit verfeinert und aktualisiert werden, um sicherzustellen, dass die Arbeit zeitgerecht fertiggestellt wird. Die endgültige Fassung der Masterarbeit soll nicht später als 31. Mai 2021 abgegeben werden. JOHANNES KEPLER UNIVERSITÄT LINZ Altenberger Straße Linz, Österreich DVR

4

5 Eidesstattliche Erklärung Ich erkläre an Eides statt, dass ich die vorliegende Masterarbeit selbstständig und ohne fremde Hilfe verfasst, andere als die angegebenen Quellen und Hilfsmittel nicht benutzt bzw. die wörtlich oder sinngemäß entnommenen Stellen als solche kenntlich gemacht habe. Die vorliegende Masterarbeit ist mit dem elektronisch übermittelten Textdokument identisch. Linz, April 2021 Unterschrift i

6

7 Danksagungen Ich möchte meinem Betreuer, Herrn o.univ.-prof.dr. Hanspeter Mössenböck, danken, dass ich die Möglichkeit hatte, diese Arbeit bei ihm zu schreiben. Besonderes schätzte ich die schnelle Beantwortung von s und die Möglichkeit, recht spontane Meetings über Zoom abzuhalten. Dank gilt natürlich auch der Firma Automated Software Testing und insbesondere Johannes Bergsmann und David Thiel, da ich dort 7 Monate arbeiten durfte und sie mir in zahlreichen Meetings geholfen haben, meinen Code zu schreiben. Besonderer Dank geht auch noch an Johannes Hochrainer, der eng mit mir zusammengearbeitet hat und mir bei meinen zahlreichen Fragen stets zur Seite stand. Schlussendlich möchte ich mich auch noch bei meiner Familie bedanken, welche mich mein ganzes Studium unterstützte. Vor allem auch bei meiner Frau Rebekka, die sich etliche Vorträge anhören musste und den Text korrekturgelesen hat, obwohl sie meistens nichts verstehen konnte. Zusätzlich war sie noch die gesamte Dauer meiner Arbeit schwanger, schaffte es aber trotzdem, mir immer den Rücken freizuhalten, sodass ich die Möglichkeit hatte, zügig voranzukommen. Als Letztes möchte ich auch noch meiner Tochter Amelie danken, da sie mir durch ihre bevorstehende Geburt, die notwendige Motivation gab, auch wirklich fertig zu werden. ii

8

9 Kurzfassung Da Software Projekte immer größer werden, wird es stets schwieriger sie zu testen und damit auch zunehmend teurer, da mehr Entwicklungszeit investiert werden muss. Devmate ist ein Werkzeug, welches Entwicklern hilft, Unit Tests zu erstellen, indem Methodensignaturen analysiert und mithilfe von Äquivalenzklassen automatische Testfälle erstellt werden. Obwohl Devmate zum Teil sprachneutral aufgebaut ist, unterstützte es zunächst nur C#. Das Ziel dieser Arbeit war, es um die Funktionalität für Java zu erweitern. Dafür wurden zwei Plug-ins für Eclipse und IntelliJ geschrieben, sowie ein Code-Generator, welcher Test-Klassen für JUnit 5 erstellt. Abstract As software projects tend to grow, it is more and more difficult to test them adequately. This also makes development more expensive, as time to test can t be used to develop new software. Devmate is a tool which helps developers with creating Unit tests from method signatures. It uses equivalence classes to automatically generate test cases. Devmate is partly language independent, but initially only supported C#. The goal of this thesis was to extend Devmate, so that it supports also Java. For that, two plug-ins were developed, one for Eclipse and one for IntelliJ. In addition to that, a Code Generator, which creates JUnit 5 classes was written. 1

10

11 Inhaltsverzeichnis Kurzfassung 1 Abstract 1 1 Einführung 5 2 Hintergrund Testen White-Box-Testen Black-Box-Testen Xtend Devmate Benutzung Architektur Implementierung Model-Builder Eclipse IntelliJ Beispiel Test-Generator Code-Generator Testmethodik Weiterführende Arbeiten CodeMerge Java Plug-ins für weitere IDEs Weitere Test-Frameworks für den Code-Generator Erweiterung des Eclipse Plug-ins um auch C/C++ zu unterstützen Zusammenfassung 58 7 Verzeichnisse 60 3

12

13 1 Einführung Da Software heute immer größer wird und immer mehr Codezeilen enthält, ist es auch immer schwieriger zu überprüfen, ob der Code auch tatsächlich das macht, was er soll. Code musste schon immer getestet werden, aber mit wachsender Größe wird auch diese Aufgabe immer komplexer. Es ist nicht zumutbar, nach jeder Änderung alle Use-Cases manuell zu überprüfen, da dies viel zu viel Zeit in Anspruch nimmt. Deswegen werden Tests geschrieben, welche automatisch überprüfen, ob der Code den Anforderungen entspricht und keine Fehler enthält. Aber auch diese Tests zu schreiben ist aufwendig und es können leicht Anwendungs- und Spezialfälle übersehen werden. Aus diesem Grund sind Werkzeuge hilfreich, welche einen Teil dieser mühseligen Arbeit abnehmen, indem sie automatisiert Testfälle erstellen. Damit können sich die Entwickler mehr auf die wesentlichen Dinge, wie das Schreiben des Codes, konzentrieren. Devmate [2] ist solch ein Werkzeug. Es soll Entwicklern helfen, Black-Box-Testfälle für Methoden zu generieren (siehe Abschnitt 2.1.2). Dafür muss der Benutzer nur verschiedene Äquivalenzklassen für die Parameter der Methode definieren und Repräsentanten für diese festlegen (siehe Abschnitt 2.1.2). Devmate kann dann automatisch Testfälle erstellen und eine gültige Testklasse generieren. Vor diesem Projekt unterstützte Devmate nur die Programmiersprache C# [13]. Obwohl C# viele Entwickler benutzen, gibt es andere Sprachen, welche häufiger benutzt werden [21]. Um mehr potenzielle Kunden zu gewinnen und Devmate vielseitiger zu machen, war das Ziel dieser Arbeit, Devmate um die Sprache Java [18] zu erweitern. Diese ist, laut Oracle, die Nummer 1 der Programmiersprachen und wird von 12 Millionen Entwicklern und 5 Millionen Studenten benutzt [19]. Devmate selbst wurde auch großteils in Java geschrieben. Dies stellt eine weitere Bereicherung dar, da die Entwickler, Devmate nun auch mit ihrem eigenen Werkzeug testen können. Im Zuge dieser Arbeit wurden folgende Funktionen implementiert: 1. Zwei Model-Builder, jeweils einer für IntelliJ [10] und Eclipse [6]. Diese bestehen aus einem Parser und einem Mapper, welche den bestehenden AST (Abstract Syntax Tree) auf den von Devmate verwendeten GAST (Generic AST) abbilden (Abschnitt 4.1). 2. Einen Code-Generator, welcher aus den in Devmate definierten Testfällen, JUnit- Testfälle generiert (Abschnitt 4.3). 3. Eine Verbindung der neu geschrieben Teile, mit dem sprachunabhängigen Test- Generator (Abschnitt 4.2). 5

14

15 2 Hintergrund In diesem Kapitel werden einige Begriffe zum Thema Testen erklärt. Zusätzlich wird XTend vorgestellt, da es für den Code-Generator verwendet wurde (siehe Abschnitt 4.3). 2.1 Testen Beim Testen wird ein System, mit dem Ziel Fehler zu finden, ausgeführt [15]. Es gibt verschiedene Methoden, um ein System zu testen. Welche man verwendet, hängt vor allem davon ab, was genau getestet werden soll, welche Fehler man finden möchte und welche Rolle man in dem Projekt einnimmt. Im Gegensatz zu statischen Testtechniken, welche Programmierstil und Komplexität beurteilen ohne den Code ausführen zu müssen, betrachten dynamische Testtechniken die Interaktion mit dem zu testenden Objekt. Im Folgenden werden zwei gegensätzliche Testmethoden betrachtet: White-Box-Testen Beim White-Box-Testen ist der Quellcode des zu testenden Systems bekannt. Dadurch ist es am besten geeignet, wenn auch die Entwickler selbst testen, da sie den Quellcode schon kennen und dieser nicht weitergegeben werden muss. Getestet wird vor allem die Struktur und welche Pfade im Programm genommen werden. Ziel ist es, eine möglichst große Codeabdeckung zu erreichen, indem versucht wird jeden möglichen Pfad zumindest einmal auszuführen. Abdeckungsarten sind Anweisungsabdeckung, Zweigabdeckung und Pfadabdeckung [20] Black-Box-Testen Im Gegensatz zu White-Box-Tests liegt bei Black-Box-Tests der Quellcode des zu testenden Systems nicht vor. Es sind nur die Ein- und Ausgangsparameter bekannt, während die interne Struktur versteckt ist. Getestet wird, ob die Ausgangsparameter, bei bestimmten Werten der Eingangsparameter, den Wert haben welcher durch die Spezifikationen definiert ist. Daher muss der Tester selbst kein Entwickler sein und kann auch ohne Zugriff auf den Quellcode testen. Es reicht, die Schnittstelle des Testobjekts zu kennen [20]. Äquivalenzklassen Da es oft undenkbar ist, alle Werte der Eingangsparameter zu testen, werden Methoden verwendet, um mit wenigen Testfällen möglichst viele Eingabevarianten abzudecken. Die 7

16 Idee dahinter ist, dass es Äquivalenzklassen gibt, für welche alle Werte dieser Klasse dasselbe Ergebnis liefern [15]. Mit folgendem Beispiel wird dies näher erklärt: In Österreich brauchen Kinder bis zu einem Alter von 14 Jahren einen Kindersitz [16]. Als Äquivalenzklassen haben wir nun für das Alter den Bereich 0-14 und größer 15. Zusätzlich existiert noch der Fall der ungültigen Eingabe mit dem Alter kleiner 0. Es reichen daher, zum Beispiel die Werte 7 und 25 zu testen. Es gibt aber zusätzlich die Regel, dass Kinder ab einer Körpergröße von 1,35 m, unabhängig von ihrem Alter, keinen Kindersitz mehr brauchen. Daher gibt es hier zusätzliche Äquivalenzklassen, welche aber auch abhängig von den vorherigen sind. Wie man in Tabelle 1 sieht, würde man mit der Kombination dieser beiden Parameter, sechs Äquivalenzklassen bekommen, da bei ungültigen Parameterwerten der Wert des jeweils anderen Parameters unerheblich ist. Äquivalenzklasse Alter (Jahre) Größe (cm) Benötigt Kindersitz Repräsentanten X Ja 7 95 X Nein X Nein X Nein X5 <0 egal Ungültig X6 egal <0 Ungültig Tabelle 1: Äquivalenzklassen für eine Methode welche angibt, ob ein Kindersitz gebraucht wird Grenzwertanalysen Aus Erfahrung weiß man, dass die meisten Fehler an den Grenzen der Äquivalenzklassen auftreten. Aus diesem Grund analysiert man diese besonders und nimmt als Repräsentanten einer Äquivalenzklasse jene Werte, welche direkt auf oder knapp neben den Grenzen liegen. In Tabelle 2 sind Repräsentanten für das vorherige Beispiel zu sehen, welche sinnvoll für die Grenzwertanalyse sind. Zusätzlich sollten auch verschieden Kombinationen dieser und der vorherigen Werte benutzt werden. Abhängig davon, wie robust getestet werden soll, können mehr oder weniger dieser Fälle betrachtet werden [12]. 8

17 Parameter <G1 G1 >G1 <G2 G2 >G2 Alter (Jahre) Größe (cm) Tabelle 2: Repräsentanten für die Grenzwerte G1=0 und G2=14 für Alter und G2=135 für Größe 2.2 Xtend Xtend ist ein Java-Dialekt, welcher nach Java 8 kompiliert und daher ohne Probleme gemeinsam mit Java in einem Projekt verwendet werden kann [8]. Xtend wurde von der Eclipse Foundation als Erweiterung für Eclipse entwickelt. Der Hauptvorteil von Xtend ist die Möglichkeit der Template-Expressions [9]. Diese erlauben Strings lesbar aneinanderzureihen ohne die umständliche Java-Syntax verwenden zu müssen. Text kann einfach so hingeschrieben werden, wie man ihn in der Ausgabe sehen will. Dies inkludiert Zeilenumbrüche und Einrückungen. Code kann im Text verwendet werden, indem er innerhalb «und» zu finden ist. Dies hilft, den Code lesbar zu halten. Im Vergleich zwischen Java und Xtend in Listing 1 und Abbildung 1 ist zu sehen, wieviel einfacher Xtend die Lesbarkeit des Codes macht. 1 pulbic static String printclass(string classname, ClassCode classcode) { 2 StringBuilder sb = new Stringbuilder(); 3 sb.append("@displayname(\"testing Method ").append(classname).append("\")").append (System.lineSeparator()); 4 sb.append("public class ").append(stringutils.capitalize(classname)).append("test {").append(system.lineseparator()); 5 sb.append("\t").append(printclasscode(classcode)).append(system.lineseparator()); 6 sb.append("}").append(system.lineseparator()); 7 return sb.tostring(); 8 } Listing 1: Beispiel Java Code Abbildung 1: Der selbe Code in Xtend 9

18

19 3 Devmate Devmate ist ein Werkzeug, welches von der Automated Software Testing GmbH entwickelt und vertrieben wird [2]. Automated Software Testing ist ein hoch innovatives Start-up aus Linz. Die Hauptaufgabe ist, Benutzern zu helfen, schneller und effektiver Unit-Tests zu schreiben, indem einige Schritte automatisiert werden, wodurch schnell viele Testfälle geschrieben werden können. Es wird das Verfahren des Black-Box-Testens (siehe Abschnitt 2.1.2) sowie die Äquivalenzklassenmethode (siehe Abschnitt 2.1.2) verwendet, um alle Kombinationen der Parameterwerte einer Methode miteinander zu verbinden. Vor dieser Arbeit existierte nur ein Plug-in für Microsoft Visual Studio und die Programmiersprache C#. Außerdem wurden bereits die Test-Frameworks NUnit [5], xunit [1] und MSTests [14] implementiert. Für die folgende Erklärung wurde dieses Plug-in [3] und das Test-Framework NUnit verwendet [5]. 3.1 Benutzung Auf der Homepage von Devmate ist der Prozess folgendermaßen beschrieben [4]: 1. Ein Modell des Codes erstellen. 2. Äquivalenzklassen und ihre Repräsentanten erstellen. 3. Die Repräsentanten in Testfälle kombinieren. 4. Die Rückgabewerte definieren. 5. Eine Test-Klasse generieren. 6. Optional: Existierenden und neuen Code verknüpfen. Die meisten dieser Schritte sind automatisiert und werden durch Klicken der entsprechenden Knöpfe ausgelöst. Nur in den Schritten 2 und 4 müssen vom Benutzer selber Daten eingegeben werden. Schritt 3 kann auch vom Benutzer übernommen werden, zusätzlich oder als Ersatz der automatisch generierten Testfälle. Im Folgenden werden die einzelnen Schritte näher beschrieben. Als Beispiel wird dabei die in Listing 2 zu sehende Methode verwendet. Listing 2: Methodensignatur für das Beispiel 1 public static double AvgSpeed(DateTime start, DateTime end, double distance) 11

20 Abbildung 2: Mit einem Klick wird das Modell erstellt 1. Modell erstellen. Wenn der Cursor sich in einer Methode befindet und das Kontextmenü aufgerufen wird, kann dort die Aktion Test with devmate ausgeführt werden (siehe Abbildung 2). Damit wird Devmate ein Modell erstellen, um den Test-Generator starten zu können. Dort kann nun der Benutzer Äquivalenzklassen und ihre Repräsentanten erstellen. 2. Äquivalenzklassen und ihre Repräsentanten erstellen. Zuerst müssen Äquivalenzklassen gebildet werden (siehe Abbildung 3). Mithilfe von Konstruktoren (siehe Abbildung 4) und Factory-Methoden (siehe Abbildung 5) können dann dafür Repräsentanten definiert werden. Factory-Methoden erlauben es, eigene Konstruktoren für komplexe Typen zu definieren. 3. Die Repräsentanten in Testfälle kombinieren. Testfälle können entweder automatisch generiert oder vom Benutzer selbst erstellt werden. Dafür wird der entsprechende Knopf gedrückt (siehe Abbildung 6). Die erstellten Tests sind in Abbildung 7 zu sehen. 4. Rückgabewerte definieren. Der Benutzer muss hier die zu erwartenden Rückgabewerte definieren, beziehungsweise angeben, welche Exceptions geworfen werden sollen (siehe Abbildung 7). 5. Eine Test-Klasse generieren. Mit Klick auf den entsprechenden Button (siehe 12

21 Abbildung 3: Äquivalenzklassen mit Repräsentanten Abbildung 4: Mithilfe von Konstruktoren können Repräsentanten definiert werden. 13

22 Abbildung 5: Erstellte Factory-Methode mit 3 Parametern: day, hour, minute Abbildung 6: Tests automatisch generieren, selber erstellen oder löschen Abbildung 7: Testfälle mit Rückgabewerte Abbildung 8: Test-Klasse generieren 14

23 Abbildung 9: Abfrage ob eine neue Test-Klasse erstellt werden soll, oder die alte mit der neuen zusammengefügt werden soll. Abbildung 8) wird die Test-Klasse erstellt. Es wird hier auch angezeigt, ob und wo der erstellte Code gespeichert wurde. Das Zahnrad rechts neben dem Knopf erlaubt es, das Test-Framework zu wechseln. Die erstellte Test-Klasse hat keine Abhängigkeit von Devmate und kann auch ohne weiterverwendet werden. Daher jeder Code der generiert wurde, ist wirklich vom Benutzer für immer verwendbar, ohne dass das Werkzeug weiter verwendet werden muss. Die generierte Test-Klasse ist in Listing 3 zu sehen. 6. Optional: Existierenden und neuen Code verknüpfen. Wenn die Test-Klasse nicht das erste Mal erstellt wurde, wird gefragt ob die alte Version überschrieben werden soll, die neue als eigene Datei gespeichert werden soll oder beide zu einer Datei zusammengefügt werden sollen (siehe Abbildung 9). Da der Benutzer die Test-Klasse in der Zwischenzeit bearbeiten konnte oder eventuell sogar bearbeiten musste (um Factory-Methoden zu implementieren) ist es hilfreich, wenn beim erneuten Generieren der Test-Klasse, dieser selbst geschriebene Code, nicht wieder gelöscht wird. 15

24 Listing 3: Generierte Test-Klasse 1 namespace AvgSpeedTestTests 2 { 3 using System; 4 using System.Collections.Generic; 5 using NUnit.Framework; 6 7 public class AvgSpeedTestCase 8 { 9 private static IEnumerable<TestCaseData> PositiveTests() 10 { 11 yield return new TestCaseData(new DateTime(2021, 1, 20, 15, 0, 0), new DateTime (2021, 1, 20, 16, 0, 0), 100, 100) 12.SetName("p1") 13.SetDescription(""); 14 yield return new TestCaseData(new DateTime(2021, 1, 20, 15, 0, 0), new DateTime (2021, 1, 20, 16, 0, 0), 0, 0) 15.SetName("p2") 16.SetDescription(""); 17 } private static IEnumerable<TestCaseData> NegativeTests() 20 { 21 yield return new TestCaseData(new DateTime(2021, 1, 20, 15, 0, 0), new DateTime (2021, 1, 19, 15, 0, 0), 0, -1) 22.SetName("n2") 23.SetDescription("end: invalid"); 24 yield return new TestCaseData(new DateTime(2021, 1, 20, 15, 0, 0), new DateTime (2021, 1, 20, 16, 0, 0), -10, -1) 25.SetName("n3") 26.SetDescription("distance: <0"); 27 } private static IEnumerable<TestCaseData> TestsThrowingException() 30 { 31 yield return new TestCaseData(new DateTime(2021, 15, 50, 30, 100, 100), new DateTime(2021, 1, 20, 16, 0, 0), 100, typeof(argumentoutofrangeexception)) 32.SetName("n1") 33.SetDescription("start: invalid"); 34 } [Test] 37 [TestCaseSource("PositiveTests")] 38 [TestCaseSource("NegativeTests")] 39 public void AvgSpeedTest(DateTime start, DateTime end, Double distance, Double expected) 40 { 41 Double actual = CSharpTutorials.Program.AvgSpeed(start, end, distance); 42 Assert.AreEqual(expected, actual); 43 } 44 16

25 45 [Test] 46 [TestCaseSource("TestsThrowingException")] 47 public void AvgSpeedTestThrowingException(DateTime start, DateTime end, Double distance, Type expected) 48 { 49 Assert.Throws(expected, () => CSharpTutorials.Program.AvgSpeed(start, end, distance)); 50 } 51 } 52 } 3.2 Architektur Da der Test-Generator IDE- und sprachunabhängig ist, benötigt er eine Schnittstelle, die mit allen Eventualitäten der jeweiligen Sprachen umgehen kann. Dafür wurde ein Modell verwendet, welches an das Modell des Abstract Syntax Trees (AST) der Object Managment Group (OMG) [17] angelehnt ist. Es wurden dabei aber Änderungen vorgenommen, um es besser auf die Bedürfnisse von Devmate zuzuschneiden. Deshalb wurden einige Klassen durch Attribute ersetzt und alle Typen erhielten den Suffix Type. Dieser AST wird "generic AST (GAST)"genannt. Jedes Objekt der Klasse Type (siehe Abbildung 10) hat mehrere Attribute: fullname: Der voll qualifizierte Name des Typs. Bei primitiven Typen, ist er identisch mit dem Namen. Da dieser eine eindeutige ID ist, muss immer nur der Name gespeichert werden, um den passenden Typ zu verlinken. name: Der Name des Typs. asttypename: Die Bezeichnung des Typs in diesem Diagramm (daher: Integer- Type, ClassType und weitere). Dadurch wird in jeder Sprache, der entsprechende Typ übernommen. nullable: Boolean, der anzeigt ob der Wert des Typs null sein darf. throwable: Boolean, der anzeigt, dass es sich hier um eine Exception handelt. Es werden nun einzelne Typen näher erklärt und auf die Verwendung für Java eingegangen, bei welchen dies nicht offensichtlich ist. EnumType: Beinhaltet eine Liste an möglicher Literalen. Ein Literal ist ein String. Eine Instanz dieses Typs, ist einer der hier definieren Literalstrings. NumberType: In Java sind alle Zahlentypen immer mit einem Vorzeichen versehen. 17

26 18 Abbildung 10: Übersicht über Type und alle Abhängigkeiten

27 RealType: Fließkommazahlen mit dem Attribut precision. Dieses enthält die Anzahl der Bits, welche nach dem Komma gespeichert sind. Eine äquivalente Klasse zu LongDouble existiert in Java nicht. IntegralType: Ganzzahlen mit dem Attribut size. Dieses beschreibt die Anzahl der Bits, welche für diesen Typ benötigt werden. StringType: Ist hier ein eigener Typ, anstatt wie in Java einfach eine Klasse zu sein. Dadurch wird kein Konstruktor gebraucht, sondern Strings können einfach eingetippt werden. ConstructedType: Typen die aus einem Zusammenschluss mehrerer Typen bestehen. elementtype ist dabei der voll qualifizierte Name des Typs des Elements. Beim Parsen muss auch der Element-Typ geparst werden. In Java wird dies vor allem für Arrays benötigt. Generische Typen wurden in dieser Arbeit noch nicht implementiert. ClassType: In objektorientierten Sprachen, wie zum Beispiel Java, sind Klassen ein sehr wichtiger Typ. Die Liste der Konstruktoren erlaubt es, im Test-Generator Instanzen davon anzulegen. Dafür müssen auch jeweils alle Parameter der Konstruktoren geparst werden, damit deren Typen bekannt sind und die Konstruktoren verwendet werden können. Diese Typen werden an die eigentliche Schnittstelle, die Klasse TestItem, übergeben und dort als Liste gespeichert. 1. TestItem (siehe Abbildung 11) beschreibt eine zu testende Methode: id: Ein String im UUID Format, welcher für dieses TestItem global eindeutig ist. name: Der Name der zu testenden Methode. uri: Der Speicherort der Klasse, welche die Methode enthält. isstatic: Definiert ob es sich um eine statische oder nicht statische Methode handelt. inputs: Für jeden Parameter wird ein Port angelegt und in dieser Liste gespeichert. Zusätzlich wird als erster Parameter die Instanz der Klasse gespeichert, wenn die Methode nicht statisch ist. outputs: Für den Rückgabewert wird auch ein Port angelegt. 19

28 Abbildung 11: TestItem tests: Eine Liste jener Tests, die für die Methode im Test-Generator angelegt wurden. types: Eine Liste an Datentypen, welche mit dem TestItem assoziiert werden. Dies beinhaltet die Klasse, in welcher sich die Methode befindet, die Typen der Parameter des Rückgabewerts, der geworfenen Exceptions und der Standard Exceptions der jeweiligen Sprache. Zusätzlich natürlich alle Typen, die im Konstruktor eines anderen Typs benötigt werden. 2. Ports dienen zur Definition von Parametern der Eingabe- und Ausgabewerte. id: Eine fortlaufende Zahl um den Port eindeutig identifizieren zu können. name: Der Name des Parameters der Methode, beziehungsweise expected für den Rückgabewert und instance für die Instanz bei nicht statischen Methoden. fulltypename: Der voll qualifizierte Name des Typs, um ihn in der Liste der Typen zu finden. actualparametermodifier: Ein Modifier, der dem Parameter zusätzliche Bedeutung gibt. Wwird in Java nicht benötigt und daher nicht gesetzt. 20

29 3. Test ist im Prinzip eine Test-Suite und damit eine Ansammlung von Tests. name: Der Name der Test-Suite. description: Eine Beschreibung der Test-Suite. date: Das Datum, wann der Test erstellt wurde. testcases: Eine Liste aus TestCases. 4. testcase ist ein konkreter Testfall. name: Der Name des Testfalls. description: Eine Beschreibung des Testfalls. Muss nicht gesetzt werden. inputs: Eine Liste von Testdaten, welche die Inputdaten für den Testfall beschreibt. output: Das erwartete Ergebnis des Testfalls. exception Die erwartete Exception des Testfalls (an Stelle des output ). 5. TestData ist der Wert eines Ports für einen Testfall. 6. Exception ist eine geworfene Exception für einen Testfall. Der Typname muss in der Liste der Typen enthalten sein. value: Der Wert für den Testfall. Die Struktur der Instanz muss der Typdefinition des Typen an diesem Port entsprechen. portid: Die Referenz auf einen Port. 21

30

31 4 Implementierung Devmate besteht im Groben aus 3 Teilen, welche relativ unabhängig voneinander entwickelt werden können: 1. Model-Builder: Besteht aus Parser und Mapper welche IDE- und sprachabhängig sind. Diese sorgen dafür, dass ein TestItem-Objekt erstellt wird, das alle Informationen aus der Methodensignatur, der zu testenden Methode, enthält, welche benötigt werden um den Test-Generator zu starten (siehe Abschnitt 4.1). 2. Test-Generator: Dieser Teil ist IDE- und sprachunabhängig und daher kann der bestehende Code übernommen werden. Die meiste Interaktion mit dem Benutzer erfolgt hier, da er Äquivalenzklassen definieren und ihre Repräsentanten erstellen kann. Zusätzlich werden hier auch die Tests, entweder vom Benutzer oder auch automatisch, erstellt (siehe Abschnitt 4.2). 3. Code-Generator: Mithilfe der definierten Tests, wird dann gültiger Test-Code erstellt und in einer Datei gespeichert (siehe Abschnitt 4.3). Zusätzlich wurde in dieser Masterarbeit ein Plug-in für die gewählte IDE implementiert, welches all diese Teile und die Kommunikation zwischen diesen, enthält. In Zuge dieser Arbeit wurden Plug-ins für IntelliJ und Eclipse entwickelt. Es existieren bereits Pläne für weitere IDEs (siehe Abschnitt 5.2). In diesem Kapitel wird die in Listing 4 zu sehende Methode, CheckAppointment der Klasse AppointmentChecker, als Beispiel genommen. Listing 4: zu testende Methode 1 package meetingcalculator; 2 3 import java.util.arraylist; 4 import java.util.list; 5 6 public class AppointmentChecker { 7 public MeetingAppointment[] currentcalenderentries; 8 9 public AppointmentChecker(MeetingAppointment[] currentcalendarentries) { 10 this.currentcalenderentries = currentcalendarentries; 11 } // die zu testende Methode 14 public boolean CheckAppointment(MeetingAppointment meeting) throws Exception { 15 if (currentcalenderentries == null) throw new Exception("Calendar can not be null"); 16 if (meeting == null) return false; 23

32 17 18 for (MeetingAppointment cur : currentcalenderentries) { 19 if (cur.getstarttime().isafter(cur.getendtime())) throw new Exception(" Start must be before End"); 20 if (meeting.getstarttime().isafter(meeting.getendtime())) throw new Exception("Start Time of Meeting2Check must be before End Time"); if (meeting.getstarttime().isafter(cur.getstarttime()) && meeting. getstarttime().isbefore(cur.getendtime())) { 23 return false; 24 } 25 if (cur.getstarttime().isafter(meeting.getstarttime()) && cur.getstarttime ().isbefore(meeting.getendtime())) { 26 return false; 27 } 28 } 29 return true; 30 } 31 } 4.1 Model-Builder Der Model-Builder besteht aus Parser und Mapper. Der Parser sorgt dafür, dass aus der Methodensignatur ein AST erstellt wird. Hier konnten die bereits zur Verfügung stehenden Tools der jeweiligen IDEs benutzt werden. Es wird dann ein TestItem-Objekt erstellt. Dieses bekommt die Informationen des spezifischen ASTs und der Mapper sorgt dann dafür, dass jeder Typ auf den passenden generischen Typ der Klasse Type, abgebildet wird. Beim TestItem wird tests noch nicht gesetzt, da das ja erst im Test-Generator passiert. Daher müssen nur die Ports für die Parameter und den Rückgabewert gesetzt, die Typen definiert, sowie die einfachen Felder des TestItems gesetzt werden (siehe Abbildung 12). Die Felder des TestItems werden dabei wie folgt gesetzt: id: Eine UUID wird zufällig angelegt. name: Der Name der zu testenden Methode. uri: Der Speicherort der Klasse wurde beim Event, welches den Parser startet, mitgegeben. isstatic: Die Modifiers der Methode werden nach dem Keyword static durchsucht. Der Wert ist true, wenn er gefunden wurde, ansonsten ist er false. inputs: Für jeden Parameter wird ein Port angelegt und in dieser Liste gespeichert. 24

33 Abbildung 12: Teil der TestItem Klasse, der hier relevant ist. Zusätzlich wird als erstes die Instanz der Klasse gespeichert, wenn die Methode nicht statisch ist. outputs: Für den Rückgabewert wird auch ein Port angelegt. tests: Wird hier noch nicht gesetzt, sondern erst im Test-Generator. types: Eine Liste der gefundenen Typen. Intern wird zuerst eine Map gebildet, welche den vollständigen Namen als Key verwendet. Sobald alle Typen gefunden wurden, wird hier das Value-Set als Liste übergeben. Die Ports für Parameter, Rückgabewert und eventuell die Instanz werden folgendermaßen angelegt: id: Es wird ein statischer Zähler verwendet, der bei 0 beginnt und bei jeder Initialisierung der Klasse Port um eins erhöht wird. name: Der Name des Parameters der Methode, beziehungsweise expected für den Rückgabewert und instance für die Instanz bei nicht statischen Methoden. fulltypename: Der TypMapper gibt den GAST Typ für diesen Typ zurück. Hier wird dessen voller Name gespeichert, um den Typ später wieder zu finden. actualparametermodifier: Wird nicht benötigt. Die weiteren Schritte des Parsers und Mappers sind abhängig von der IDE und werden in den nächsten Abschnitten erklärt. 25

34 Abbildung 13: Test with Equivalence Class Method Eclipse Für das Eclipse Plug-in wurde als Parser der ASTParser von Eclipse JDT [7] verwendet. Damit lässt sich ganz einfach ein AST der Java-Klasse erstellen, in der sich die zu testende Methode befindet. Zusätzlich erlaubt er auch, Bindungen aufzulösen, um die verwendeten Typen ihren Definitionen zuzuweisen, da dies benötigt wird. Gestartet wird Devmate, indem mit Rechtsklick im Kontextmenü, die Option Test with Equivalence Class Method ausgewählt wird (siehe Abbildung 13). Dies löst ein Eclipse Event aus, welches den Parser mit den Parametern file (die Datei in der das Event ausgelöst wurde) und cursorposition (die Position des Cursors in dem Moment) startet. Eclipse JDT baut einen AST über die Datei auf und stellt alle Methoden dieser Klasse bereit. Dann wird die zu testende Methode anhand der Position des Cursors gefunden oder eine Fehlermeldung ausgegeben, falls das Event außerhalb einer Methode ausgeführt wurde. In Listing 5 ist der erstellte AST für die Klasse AppointmentChecker zu sehen (siehe Listing 4 für den Code). Die Körper der Methoden wurden hier aber ausgelassen, da sie für das Beispiel irrelevant sind. Listing 5: Der erzeugte AST des Beispiels. 1 TypeDeclaration: AppointmentChecker 2 Modifiers: {public} 3 Modifier: public 4 interface: false 5 name = SimpleName: "AppointmentChecker" 6 Bodydeclarations: 7 FieldDeclaration: currentcalendarentries 8 Modifiers: {public} 9 Modifier: public 10 type = ArrayType: MeetingAppointment[] 11 elementtype = SimpleType: 12 name = SimpleName: "MeetingAppointment" 13 Fragments: 26

35 14 VariableDeclarationFragment: 15 name = SimpleName: "currentcalendarentries" 16 MethodDeclaration: AppointmentChecker 17 Modifiers: {public} 18 Modifier: public 19 constructor = true 20 name = SimpleName: AppointmentChecker 21 Parameters 22 SingleVariableDeclaration: 23 type = ArrayType: MeetingAppointment[] 24 elementtype = SimpleType: 25 name = SimpleName: "MeetingAppointment" 26 name = SimpleName: "currentcalendarentries" 27 body = {...} 28 MethodDeclaration: CheckAppointment 29 Modifiers: {public} 30 Modifier: public 31 constructor = false 32 returntype2 = PrimitiveType 33 primitivetypecode: boolean 34 name = SimpleName: "CheckAppointment" 35 Parameters 36 SingleVariableDeclaration: 37 type = ArrayType: MeetingAppointment[] 38 elementtype = SimpleType: 39 name = SimpleName: "MeetingAppointment" 40 name = SimpleName: "meeting" 41 ThrownExceptionsTypes: 42 SimpleType: 43 name = SimpleName: "Exception" 44 body = {...} Der TypeMapper wird für jeden gefundenen Typ im AST aufgerufen. Er überprüft zuerst ob der mitgegebene Typ schon in der TypMap vorhanden ist. Sollte das nicht der Fall sein, wird die Bindung des Typs aufgelöst, um die Klasse des Typen zu bekommen. Mit dieser Information wird ein neuer Typ erstellt, der in die TypMap eingefügt wird. Die Klasse org.eclipse.jdt.core.dom.ast kennt unter anderem alle primitiven Typen, sowie auch die Klasse java.lang.string, welche im GAST wie ein primitiver Typ behandelt wird. Daher kann für diese bekannten Typen direkt eine Instanz des passenden Typs im GAST angelegt werden. Alle Informationen, die der entsprechende Typ benötigt, sind direkt im Code verankert, da sie für diese Typen immer gleich sind. Ein Beispiel für so eine Mapper-Methode ist in Listing 6 zu sehen. Listing 6: IntegerMapper 1 Type mapinteger() { 2 IntegerType type = new IntegerType(); //der Typ im GAST 3 //der Name des Typs im GAST 4 type.setasttypename("integertype"); 27

36 5 type.setfullname("int"); //der voll qualifizierte Name 6 type.setname("int"); //der einfache Name 7 type.setnullable(false); //ob der Typ ``null'' sein darf 8 type.setsign(true); //in Java immer wahr 9 type.setsize(32); //der Speicher in Bits 10 type.setthrowable(false); //nur bei Exceptions wahr 11 return type; 12 } Sollte der gesuchte Typ keinem der primitiven Typen entsprechen, wird überprüft, ob es sich um ein Array oder ein Enum handelt. Wenn auch dies nicht zutrifft, wird der allgemeine ClassMapper aufgerufen. Im ArrayMapper wird ein ArrayType angelegt. Der Typ des Elements wird wieder im TypeMapper bestimmt und dessen Name als Referenz in ElementFullTypeName gespeichert (siehe Listing 7). Listing 7: ArrayMapper 1 Type maparray(itypebinding binding) { 2 //mapping des ElementTyps 3 Type elementtype = typemapper.map(binding.getelementtype()); 4 ArrayType type = new ArrayType(); 5 type.setasttypename("arraytype"); 6 type.setfullname(binding.getqualifiedname()); 7 type.setname(binding.getname()); 8 type.setelementfulltypename(elementtype.getfullname()); 9 type.setnullable(true); 10 type.setthrowable(false); 11 return type; 12 } Im EnumMapper werden die Enum-Literale, welche im AST als Felder der Klasse vorhanden sind, mit ihrem Namen als Wert in einer Liste gespeichert (siehe Listing 8). Listing 8: EnumMapper 1 Type mapenum(itypebinding binding) { 2 EnumType type = new EnumType(); 3 type.setasttypename("enumtype"); 4 type.setname(binding.getname()); 5 type.setfullname(binding.getqualifiedname()); 6 type.setnullable(true); 7 type.setenumliterals(getenumerators(binding)); 8 return type; 9 } List<EnumLiteral> getenumerators(itypebinding binding) { 12 ArrayList<EnumLiteral> list = new ArrayList<>(); 13 if (binding.isenum()) { 14 IVariableBinding[] fields = binding.getdeclaredfields(); 28

37 15 for (IVariableBinding field : fields) { 16 list.add(new EnumLiteral().value(field.getName())); 17 } 18 } 19 return list; 20 } Wenn keiner der vorher genannten Typen passt, wird der allgemeine ClassMapper aufgerufen. Im ClassMapper wird der Name und der voll qualifizierte Name der Klasse, gespeichert. Um später Instanzen der Klasse erzeugen zu können, werden alle Konstruktoren die nicht private sind, gespeichert. Dort müssen dann auch jeweils die Parameter des Konstruktors mitgegeben und neue Typen, die dort vorkommen, gemappt werden. Der ClassMapper ist in Listing 9 zu sehen. Listing 9: ClassMapper 1 Type mapclass(itypebinding binding) { 2 ClassType type = new ClassType(); 3 type.setasttypename("classtype"); 4 type.setname(binding.getname()); 5 type.setfullname(binding.getqualifiedname()); 6 type.setnullable(true)); 7 type.setthrowable(false); 8 9 boolean ispublicconstructor; 10 IMethodBinding[] methods = binding.getdeclaredmethods(); 11 for (int i=0; i<methods.length; i++) { 12 ispublicconstructor = methods[i].isconstructor() &&!Modifier.isPrivate(methods[i ].getmodifiers()); 13 if (ispublicconstructor) { 14 type.addconstructorsitem(new Constructor().parameters(createMemberList(methods[i ].getmethoddeclaration()))); 15 } 16 } 17 return type; 18 } private List<Member> creatememberlist(imethodbinding imethodbinding) { 21 List<Member> memberlist = new ArrayList<>(); 22 ITypeBinding[] parameters = imethodbinding.getparametertypes(); 23 for (ITypeBinding parameter : parameters) { 24 typemapper.map(parameter); 25 Member member = new Member(); 26 member.setname(parameter.getname()); 27 member.setfulltypename(parameter.getqualifiedname()); 28 memberlist.add(member); 29 } 30 return memberlist; 31 } 29

38 Abbildung 14: Test with Devmate Geworfene Exceptions sind zwar auch ClassTypes, haben aber ihren eigenen Mapper. Dort wird throwable auf true gesetzt. Konstruktoren werden nicht gespeichert, da diese nicht benötigt werden. Dieser Mapper wird anders aufgerufen, da Exceptions nur nach dem throws in der Methodensignatur, vorkommen dürfen. In Listing 10 wird der Code im Parser gezeigt, der es erlaubt, die Exceptions zu mappen. Listing 10: Die geworfenen Exceptions der Methode werden gemappt 1 for (Object o : methoddeclaration.thrownexceptiontypes()) { 2 if (o instanceof SimpleType) { 3 addexceptiontype((simpletype) o); 4 } 5 } IntelliJ IntelliJ benutzt das Program Structure Interface (PSI). PSI ist eine zusätzliche Schicht, welche verantwortlich für das Parsen der Dateien ist und die das syntaktische und semantische Codemodell erstellt [11]. Dies erleichtert die Verwendung des darunter liegenden ASTs. Das Tool wird gestartet, wenn im Kontextmenü die Funktion Test with Devmate ausgewählt wird (siehe Abbildung 14). Dies löst eine Aktion aus, welche den Java-Parser mit der zu testenden Methode startet oder einen Fehler ausgibt, falls das Kommando außerhalb einer Methode gestartet wurde. In Listing 11 ist die erstellte PSI-Struktur für die Klasse AppointmentChecker zu sehen (siehe Listing 4 für den Code). Die Körper der Methoden wurden hier aber ausgelassen, da sie für das Beispiel irrelevant sind. 30

39 Listing 11: Die erzeugte PSI-Struktur des Beispiels. 1 PsiClass: AppointmentChecker 2 PsiModifierList: public 3 PsiIdentifier: "AppointmentChecker" 4 PsiJavaToken:LBRACE 5 PsiField: currentcalendarentries 6 PsiModifierList: public 7 PsiTypeElement: MeetingAppointment[] 8 PsiTypeElement: MeetingAppointment 9 PsiIdentifier: "MeetingAppointment" 10 PsiIdentifier: "currentcalendarentries" 11 PsiMethod: AppointmentChecker 12 PsiModifierList: public 13 constructor = true 14 PsiIdentifier: AppointmentChecker 15 PsiParametersList:(MeetingAppointment[] currentcalendarentries) 16 PsiParameter: currentcalendarentries 17 PsiTypeElement: MeetingAppointment[] 18 PsiTypeElement: MeetingAppointment 19 PsiIdentifier: "MeetingAppointment" 20 PsiIdentifier: "currentcalendarentries" 21 PsiCodeBlock = {...} 22 PsiMethod: CheckAppointment 23 PsiModifierList: public 24 PsiTypeElement: boolean 25 PsiIdentifier: "CheckAppointment" 26 PsiParametersList:(MeetingAppointment meeting) 27 PsiParameter: currentcalendarentries 28 PsiTypeElement: MeetingAppointment 29 PsiIdentifier: "MeetingAppointment" 30 PsiIdentifier: "meeting" 31 PsiReferenceList: 32 PsiJavaCodeReferenceElement: Exception 33 PsiIdentifier: "Exception" 34 PsiCodeBlock = {...} 35 PsiJavaToken:RBRACE Der TypeMapper wird für jeden gefundenen Typ im AST aufgerufen. Er überprüft zuerst, ob der mitgegebene Typ schon in der TypMap vorhanden ist. Sollte das nicht der Fall sein, wird ein neuer Typ erstellt, der in die TypMap eingefügt wird. Dazu wird als erstes geprüft, ob der Typ ein Array ist oder einem primitiven Typen entspricht. Dazu wird dieser mit den in com.intellij.psi.psitype gespeicherten Konstanten verglichen. Für die primitiven Typen kann direkt eine Instanz des passenden Typs im GAST angelegt werden. Alle Information, die der entsprechende Typ benötigt, sind direkt im Code verankert, da sie für diese Typen immer gleich sind. Ein Beispiel für so eine Mapper- Methode ist in Listing 12 zu sehen. Listing 12: IntegerMapper 31

40 1 Type mapinteger() { 2 IntegerType type = new IntegerType(); //der Typ im GAST 3 //der Name des Typs im GAST 4 type.setasttypename("integertype"); 5 type.setfullname("int"); //der voll qualifizierte Name 6 type.setname("int"); //der einfache Name 7 type.setnullable(false); //ob der Typ ``null'' sein darf 8 type.setsign(true); //in Java immer wahr 9 type.setsize(32); //der Speicher in Bits 10 type.setthrowable(false); //nur bei Exceptions wahr 11 return type; 12 } Im ArrayMapper wird ein ArrayType angelegt. Der Typ des Elements wird wieder im TypeMapper bestimmt und der Name als Referenz in ElementFullTypeName gespeichert (siehe Listing 13). Listing 13: ArrayMapper 1 Type maparray(psiarraytype arraytype) { 2 Type elementtype = typemapper.map(arraytype.getcomponenttype()); //mapping des ElementTyps 3 ArrayType type = new ArrayType(); 4 type.setasttypename("arraytype"); 5 type.setfullname(arraytype.getcanonicaltext()); 6 type.setname(arraytype.getpresentabletext()); 7 type.setelementfulltypename(elementtype.getfullname()); 8 type.setnullable(true); 9 type.setthrowable(false); 10 return type; 11 } Sollte der Typ weder ein Array sein noch einem der primitiven Typen entsprechen, wird dieser aufgelöst, um die dahinter-liegende Klasse zu bekommen. Diese kann nun entweder ein Enum sein, der Klasse java.lang.string (welche im GAST als primitiver Typ verwendet wird) oder einer anderen Klasse entsprechen. Im EnumMapper werden die Enum-Literale, welche in der PSI-Struktur als Felder der Klasse vorhanden sind, mit ihrem Namen als Wert in einer Liste gespeichert (siehe Listing 14). Listing 14: EnumMapper 1 Type mapenum(psiclass psiclass) { 2 EnumType type = new EnumType(); 3 type.setasttypename("enumtype"); 4 type.setname(psiclass.getname()); 5 type.setfullname(psiclass.getqualifiedname()); 6 type.setnullable(true); 7 type.setenumliterals(getenumerators(psiclass)); 32

41 8 return type; 9 } List<EnumLiteral> getenumerators(psiclass psiclass) { 12 ArrayList<EnumLiteral> list = new ArrayList<>(); 13 PsiField[] fields = psiclass.getfields(); 14 for (PsiField field : fields) { 15 list.add(new EnumLiteral().value(field.getName())); 16 } 17 return list; 18 } Wenn keiner der vorher genannten Typen passt, wird der allgemeine ClassMapper aufgerufen. Im ClassMapper wird der Name und der voll qualifizierte Name der Klasse gespeichert. Um später Instanzen der Klasse erzeugen zu können, werden alle Konstruktoren die nicht private sind, gespeichert. Dort müssen dann auch jeweils die Parameter des Konstruktors mitgegeben und neue Typen, die dort vorkommen, gemappt werden. Der ClassMapper ist in Listing 15 zu sehen. Listing 15: ClassMapper 1 Type mapclass(psiclass psiclass) { 2 ClassType type = new ClassType(); 3 type.setasttypename("classtype"); 4 type.setname(psiclass.getname()); 5 type.setfullname(psiclass.getqualifiedname()); 6 type.setnullable(true); 7 type.setthrowable(false); 8 9 boolean ispublicconstructor; 10 for (PsiMethod method : psiclass.getconstructors()) { 11 ispublicconstructor =!method.getmodifierlist().hasmodifierproperty(psimodifier. PRIVATE); 12 if (ispublicconstructor) { 13 type.addconstructorsitem(new Constructor().parameters(createMemberList(( PsiParameter[]) method.getparameters()))); 14 } 15 } 16 return type; 17 } private List<Member> creatememberlist(psiparameter[] parameters) { 20 List<Member> memberlist = new ArrayList<>(); 21 for (PsiParameter parameter : parameters) { 22 PsiType type = parameter.gettypeelement().gettype(); 23 Member member = new Member(); 24 member.setname(parameter.getname()); 25 member.setfulltypename(type.getcanonicaltext()); 26 memberlist.add(member); 27 // Falls der Typ neu ist, wird er hier erstellt und gespeichert. 33

42 28 typemapper.map(type); 29 } 30 return memberlist; 31 } Geworfene Exceptions sind zwar auch ClassTypes, haben aber ihren eigenen Mapper. Dort wird throwable auf true gesetzt. Konstruktoren werden nicht gespeichert, da diese nicht benötigt werden. Dieser Mapper wird anders aufgerufen, da Exceptions nur nach dem throws in der Methodensignatur vorkommen dürfen. In Listing 16 wird der Code im Parser gezeigt, der es erlaubt, die Exceptions zu mappen. Listing 16: Die geworfenen Exceptions der Methode werden gemappt 1 PsiClassType[] exceptions = (PsiClassType[]) method.getthrowstypes(); 2 for (PsiType type : exceptions) { 3 addexception(type); 4 } Beispiel In den vorherigen Abschnitten wurde die von der IDE erstellte Struktur für ein Beispiel gezeigt (in Listing 5 und Listing 11). Danach wurde angegeben, wie ein TestItem in der jeweiligen IDE angelegt werden kann. In Listing 17 ist nun das erstellte TestItem zu sehen, welches in beiden Fällen gleich ist (mit Ausnahme des Attributs id, da dieses zufällig vergeben wird). Listing 17: Beispiel für ein erstelltes TestItem 1 TestItem: CheckAppointment 2 id: "7fa61db3-277e-4585-b127-44eef0f09c98" 3 name: "CheckAppointment" 4 uri: "C:\Users\Jakob\IdeaProjects\Demo\src\meetingCalculator" 5 isstatic: false 6 tests: List<Test> 7 inputs: List<Ports> 8 Port: AppointmentChecker instance 9 id: 0 10 name: "instance" 11 fulltypename: meetingcalculator.appointmentchecker 12 actualparametermodifier: null 13 Port: MeetingAppointment meeting 14 id: 1 15 name: "meeting" 16 fulltypename: meetingcalculator.meetingappointment 17 actualparametermodifier: null 18 output: Port 19 Port: boolean expected 20 id: 2 34

43 21 name: "expected" 22 fulltypename: boolean 23 actualparametermodifier: null 24 types: List<Type> 25 Type: meetingcalculator.appointmentchecker 26 fullname: "meetingcalculator.appointmentchecker" 27 name: "AppointmentChecker" 28 asttypename: "classtype" 29 nullable: true 30 throwable: false 31 DataType: 32 AggregateType: 33 ClassType: 34 constructors: List<Constructor> 35 Constructor: (MeetingAppointment[] currentcalendarentries) 36 parameters: List<Member> 37 Member: MeetingAppointment[] currentcalendarentries 38 name: "currentcalendarentries" 39 fulltypename: "meetingcalculator.meetingappointment[]" 40 Type: meetingcalculator.meetingappointment[] 41 fullname: "meetingcalculator.meetingappointment[]" 42 name: "MeetingAppointment[]" 43 asttypename: "ArrayType" 44 nullable: true 45 throwable: false 46 DataType: 47 ConstuctedType: 48 elementfulltypename: "meetingcalculator.meetingappointment" 49 ArrayType 50 Type: meetingcalculator.meetingappointment 51 fullname: "meetingcalculator.meetingappointment" 52 name: "MeetingAppointment" 53 asttypename: "ClassType" 54 nullable: true 55 throwable: false 56 DataType: 57 AggregateType: 58 ClassType: 59 constructors: List<Constructor> 60 Constructor: (DateTime starttime, DateTime endtime) 61 parameters: List<Member> 62 Member: DateTime starttime 63 name: "starttime" 64 fulltypename:"meetingcalculator.datetime" 65 Member: DateTime endtime 66 name: "endtime" 67 fulltypename:"meetingcalculator.datetime" 68 Constructor: (DateTime starttime, DateTime endtime, String appointmenttext) 69 parameters: List<Member> 70 Member: DateTime starttime 71 name: "starttime" 35

44 72 fulltypename:"meetingcalculator.datetime" 73 Member: DateTime endtime 74 name: "endtime" 75 fulltypename:"meetingcalculator.datetime" 76 Member: String appointmenttext 77 name: "appointmenttext" 78 fulltypename: "java.lang.string" 79 Type: meetingcalculator.datetime 80 fullname: "meetingcalculator.datetime" 81 name: "DateTime" 82 asttypename: "ClassType" 83 nullable: true 84 throwable: false 85 DataType: 86 AggregateType: 87 ClassType: 88 constructors: List<Constructor> 89 Constructor: (int year, int month, int day, int hour, int minute) 90 parameters: List<Member> 91 Member: int year 92 name: "year" 93 fulltypename: int 94 Member: int month 95 name: "month" 96 fulltypename: int 97 Member: int day 98 name: "day" 99 fulltypename: int 100 Member: int hour 101 name: "hour" 102 fulltypename: int 103 Member: int minute 104 name: "minute" 105 fulltypename: int 106 Type: int 107 fullname: "int" 108 name: "int" 109 asttypename: "IntegerType" 110 nullable: false 111 throwable: false 112 DataType: 113 PrimitiveType: 114 NumberType: 115 sign: true 116 IntegralType: 117 size: IntegerType 119 Type: java.lang.string 120 fullname: "java.lang.string" 121 name: "String" 122 asttypename: "StringType" 123 nullable: true 36

45 124 throwable: false 125 DataType: 126 PrimitiveType: 127 StringType 128 Type: boolean 129 fullname: "boolean" 130 name: "boolean" 131 asttypename: "BooleanType" 132 nullable: false 133 throwable: false 134 DataType: 135 PrimitiveType: 136 BooleanType 137 Type: Excepton 138 fullname: "java.lang.exception" 139 name: "Excepton" 140 asttypename: "ClassType" 141 nullable: true 142 throwable: true 143 DataType: 144 AggregateType: 145 ClassType: 146 constructors: null 4.2 Test-Generator Der Test-Generator ist die hauptsächliche Benutzeroberfläche von Devmate (siehe Abschnitt 3). Da dieser Teil sprachunabhängig ist, konnte er für diese Arbeit komplett übernommen werden. Der Test-Generator läuft auf einem Server, der mit dem Plug-in gestartet wird, wobei die Kommunikation über Web-Sockets erfolgt. Beim ersten Start, wird der Benutzer gefragt, wo er die Konfigurationsdatei (.tmdl ) speichern will. In dieser wird das zuvor generierte TestItem-Objekt, in Base64-kodiert, gespeichert. Aus dieser Datei wird eine URL (Uniform Resource Locator) generiert. Diese kann nun in einem Browser aufgerufen werden, um das Objekt zu laden und auch bei jeder Änderung automatisch das aktuelle TestItem-Objekt in der Konfigurationsdatei zu speichern. Um die Benutzerfreundlichkeit zu erhöhen, wird bei den Plug-ins ein Browser mitgeliefert, der in die IDE eingebettet, ausgeführt wird. Somit muss nicht zwischen IDE und einem externen Browser gewechselt werden, um Devmate zu benutzen. Für die Kommunikation über die Web-Sockets, gibt es eine Schnittstelle die in jeder IDE implementiert werden muss, welche das Speichern und Laden der Konfigurationsdatei, sowie das Erzeugen der URL beinhaltet. Die Einbettung des Browsers wird auch für jede IDE extra vorgenommen. Ansonsten muss dieser Teil von Devmate nicht auf IDE oder Sprache angepasst werden. Es kann daher der bereits vorhandene Code verwendet werden. 37

46 Abbildung 15: Test-Generator mit 4 erstellten Testfällen Im Test-Generator kann der Benutzer Äquivalenzklassen definieren und ihre Repräsentanten erstellen. Danach kann er sich Testfälle generieren lassen oder auch eigene erstellen. Dafür muss für jeden Testfall ein erwarteter Rückgabewert, beziehungsweise die erwartete, geworfene Exception, definiert werden. Es besteht auch die Möglichkeit, eine vorher erstellte Konfigurationsdatei zu laden, solange sich die Methodensignatur nicht geändert hat, damit nicht immer alle Einstellungen erneut vorgenommen werden müssen. In Abbildung 15 ist der Test-Generator in Benutzung zu sehen. Es wurden zwei Äquivalenzklassen für das AppointmentChecker-Objekt ( this ) erstellt und drei für den Parameter meeting des Typs MeetingAppointment. Für jede dieser Klassen wurde ein Repräsentant erstellt, der mit einem der bestehenden Konstruktoren erstellt wurde (siehe Abbildung 16). Es besteht auch die Möglichkeit eine eigene Factory-Methode zu erstellen, falls die Konstruktoren nicht ausreichend sein sollten (siehe Abbildung 17). Das TestItem-Objekt wird dabei nur insofern verändert, dass nun auch tests gesetzt ist. Der Rest bleibt dabei gleich. In Listing 18 sind nun für das Beispiel, die testcases des TestItems zu sehen, welche im TestGenerator angelegt wurden. Um das Format nicht zu sprengen, wurden dabei aber weniger interessante Teile ausgelassen. Das vorherige TestItem kann in Listing 17 gefunden werden. 38

47 Abbildung 16: Test-Generator mit 4 erstellten Testfällen Abbildung 17: Erstellte Factory-Methode mit 3 Parametern: day, hour, minute 39

48 Listing 18: Im TestGenerator definierte Testfälle. 1 testcases: List<TestCase> 2 TestCase: 3 name: "p1" 4 comment: "" 5 inputs: List<TestData> 6 TestData: 7 value: 8 fulltypename: "meetingcalculator.appointmentchecker" 9 name: "currentcalendarentries" 10 value: 11 fulltypename: "meetingcalculator.meetingappointment[]" 12 value: {...} 13 portid: 0 14 TestData: 15 value: 16 fulltypename: "meetingcalculator.meetingappointment" 17 name: "meeting" 18 value: 19 fulltypename: "meetingcalculator.datetime" 20 name: "starttime" 21 value: 22 fulltypename: "int" 23 name: year 24 value: value: 26 fulltypename: "int" 27 name: month 28 value: 2 29 value: 30 fulltypename: "int" 31 name: day 32 value: value: 34 fulltypename: "int" 35 name: hour 36 value: value: 38 fulltypename: "int" 39 name: minute 40 value: 0 41 value: {...} 42 value: 43 fulltypename: "java.lang.string" 44 name: "appointmenttext" 45 value: "Meeting" 46 portid: 1 47 output: TestData 48 TestData: 49 value: 50 fulltypename: "boolean" 40

49 51 value: true 52 portid: 2 53 exception: 54 TestCase: 55 name: "n1" 56 comment: "instance: invalid" 57 inputs: {...} 58 output: null 59 exception: 60 fulltypename: "java.lang.exception" 61 valid: false 62 TestCase: 63 name: "n2" 64 comment: "meeting: occupied" 65 inputs: {...} 66 output: TestData 67 TestData: 68 value: 69 fulltypename: "boolean" 70 value: false 71 portid: 2 72 exception: null 73 valid: false 74 TestCase: 75 name: "n3" 76 comment: "meeting: invalid" 77 inputs: {...} 78 output: null 79 exception: 80 fulltypename: "java.lang.exception" 81 valid: false 4.3 Code-Generator Nachdem der Benutzer im Test-Generator (siehe Abschnitt 4.2) die Äquivalenzklassen definiert und ihre Repräsentanten erstellt hat, kann er selbst Testfälle definieren oder diese vom Werkzeug erstellen lassen. Anschließend kann er eine gültige Test-Klasse generieren, um den Code auch ausführen zu können. Dafür wird auf den Knopf Generate Test Code gedrückt (siehe Abbildung 18), wodurch das aktuelle TestItem-Objekt an den Code-Generator gesendet wird. Dieser muss für jede Programmiersprache und zum Teil auch für jedes Test-Framework neu implementiert werden, da der daraus generierte Code davon abhängig ist. In dieser Arbeit wurde nur ein Generator für JUnit entwickelt, es wäre aber mit relativ wenig Aufwand möglich, weitere alternative Test-Frameworks für Java einzubinden (siehe Abschnitt 5.3). Vorteilhaft ist auch, dass der Code-Generator, im Gegensatz zu Parser und Mapper, IDE-unabhängig ist und daher nur einmal geschrieben werden muss und für 41

50 Abbildung 18: Generate JUnit Test Code Knopf beide in dieser Arbeit entwickelten Plug-ins direkt verwendbar ist. Der Code-Generator besteht aus vier Teilen, welche im Folgenden näher erklärt werden: 1. Das mit Testfällen bestückte TestItem, wird vom Test-Generator empfangen. 2. Aus diesem sprachunabhängigen Objekt wird nun ein TestCode-Objekt erstellt, welches auf Java angepasst wurde. 3. Daraus wird mithilfe von xtend ein String generiert, der ausführbaren JUnit 5 Testcode enthält. 4. Dieser wird abschließend in einer Datei gespeichert. Devmate verfügt darüber hinaus über ein weiteres Werkzeug (Code-Merge) das verhindert, dass vom Benutzer veränderter Code in dieser Datei überschrieben wird. Der Code- Merge muss dafür natürlich auch wieder dem Test-Framework angepasst werden, was jedoch nicht nicht mehr Teil dieser Arbeit war (siehe Abschnitt 5.1). 1. TestItem: Die TestItem-Klasse ist die direkte Schnittstelle zwischen den einzelnen Teilen, aus denen Devmate besteht. Ein Objekt dieser Klasse wird vom Parser erzeugt und vom Mapper mit den benötigten Informationen bestückt, um den Test-Generator starten zu können. Dort wurden Äquivalenzklassen und Repräsentanten vom Benutzer definiert, aus denen dann Testfälle erstellt werden konnten. Alle diese Informationen wurden automatisch im TestItem-Objekt gespeichert. Nun enthält es zusätzlich zu den Ports und den Types (siehe Abschnitt 4.2) auch noch die einzelnen Tests, die TestCases und die TestData, sowie die eventuell geworfenen Exceptions. Aus diesen generischen Daten muss jetzt ein sprachabhängiges TestCode-Objekt erstellt werden. Dies erfolgt im nächsten Schritt. 2. TestCode: 42

51 Abbildung 19: TestItem-Struktur Der TestCode-Klasse wird im Konstruktor ein TestItem übergeben. Aus diesem werden alle Information extrahiert, die in der jeweiligen Sprache benötigt werden. Für Java sind das die folgenden Punkte: testitemid: Das ist dieselbe ID wie im TestItem, um den erzeugten Code mit dem dazugehörigen TestItem in Verbindung bringen zu können. package: Der Ordner, in dem sich auch die Klasse der zu testenden Methode befindet. imports: Eine Liste aller zu importierenden Elemente. Dafür wird die Types- Liste des TestItems genommen und alle Einträge gelöscht, die in keinem Test vorkommen. Da diese Liste ja alle möglicherweise benötigten Elemente enthält, würden sonst eventuell etliche unnütze imports vorgenommen. classname: Der Name der zu erstellenden Klasse. Diese setzt sich aus dem Namen der Methode (der hier jedoch, wie es in Java für Klassen üblich ist, mit einem Großbuchstaben anfängt) und dem Wort Test zusammen. factories: Eine Liste der zu erstellenden Factory-Methoden, welche der Benutzer im Test-Generator erstellt hat. Für jede dieser Methoden wird ihre 43

52 Signatur angegeben, welche aus Name, Rückgabewert und Parametern besteht. testcasesource: Eine Liste an Quellen für die Testfälle. Davon existieren drei, wobei nicht immer alle verwendet werden müssen: Positive Testfälle, negative Testfälle und Testfälle, die eine Exception werfen. Jede dieser Quellen hat dann, für jeden im Test-Generator definierten Test der entsprechenden Kategorie, ein TestCaseData-Objekt. Dieses enthält die dort eingesetzten Werte für die Parameter, sowie den Rückgabewert, beziehungsweise den Namen der Exception, die geworfen wird. Zusätzlich ist auch der Name und die Beschreibung gespeichert, damit diese später angezeigt werden können. regulartestmethod und exceptiontestmethod: Diese beiden enthalten die tatsächlichen Test-Methoden die dann in der Test-Klasse getestet werden können. Sie werden als TestMethod-Objekte gespeichert Die erste testet alle Fälle, in denen keine Exceptions geworfen werden (d.h. die positiven und negativen Testfälle), während die zweite die Testfälle abdeckt, die Exceptions werfen. Da die Methodensignatur für diese beiden Möglichkeiten anders aussieht, müssen sie getrennt behandelt werden. Es kann sein, dass eine der beiden nicht benötigt wird und daher nicht definiert ist. Das TestMethod-Objekt enthält alle Informationen, welche benötigt werden, um die Test-Methode erstellen zu können: name: Der Name der zu erstellenden Methode. Dieser setzt sich aus dem Namen der Test-Methode und dem Wort Test zusammen. Für eine Methode, welche eine Exception wirft, wird noch zusätzlich ThrowingException angefügt. invocationofsut: Der Aufruf der zu testenden Methode, welcher davon abhängt ob diese statisch ist oder nicht. withexception: Ob diese Methode für Exceptions zuständig ist. returntype: Der Rückgabewert der zu testenden Methode. textcasesource: Welche Testdaten des TestCodes verwendet werden sollen, entweder positive und negative oder Exception werfende. formalparameters: Eine Liste der Parameter mit Typ und Name. Dies enthält die Parameter der zu testenden Methode, sowie einen zusätzlichen für den zu erwartenden Rückgabewert (falls dieser nicht void ist), beziehungsweise der Klasse der Exception, die geworfen werden soll, mit Namen expected. 44

53 Abbildung 20: TestCode Struktur argumentsofsut: Die Argumente, die der Aufruf der Methode benötigt. In Listing 19 ist das TestCode-Objekt zu sehen, welches aus dem TestItem-Objekt des Beispiels generiert wurde. Listing 19: Beispiel für ein TestCode-Objekt 1 TestCode: 2 testitemid: "7fa61db3-277e-4585-b127-44eef0f09c98" 3 package: "meetingcalculator" 4 imports: {java.lang.exception} 5 classname: "CheckAppointmentTest" 6 factories: null 7 testcasesources: List<TestCaseSource> 8 TestCaseSource: 9 name: "positivetestdata" 10 withthrowexception: false 11 testcasedatalist: List <TestCaseData> 12 TestCaseData: 13 testcasename: "p1" 14 testcasedescription: "" 15 values: {new AppointmentChecker(newMeetingAppointment [] {new MeetingAppointment(newDateTime (2021, 2, 19, 12, 0), new DateTime (2021, 2, 19, 13, 0)), new MeetingAppointment(new DateTime (2021, 45

54 2, 20, 12, 0), new DateTime(2021, 2, 20, 11, 0))}), new MeetingAppointment(new DateTime (2021, 2, 19, 11, 0), new DateTime (2021, 2, 19, 12, 0)} 16 TestCaseSource: 17 name: "negativetestdata" 18 withthrowexception: false 19 TestCaseData: 20 testcasename: "n2" 21 testcasedescription: "meeting: occupied" 22 values: {...} 23 TestCaseSource: 24 name: "throwingexceptiontestdata" 25 withthrowexception: true 26 TestCaseData: 27 testcasename: "n1" 28 testcasedescription: "instance: invalid" 29 values: {...} 30 TestCaseData: 31 testcasename: "n3" 32 testcasedescription: "meeting: invalid" 33 values: {...} 34 regulartestmethod: TestMethod 35 TestMethod: 36 name: "CheckAppointmentTest" 37 invocationofsut: "instance.checkappointment" 38 withexception: false 39 returntype: FormalParameter 40 type: "boolean" 41 name: "expected" 42 modifier: "" 43 testcasesources: {"positivetestdata", "negativetestdata"} 44 formalparameters: List<FormalParameter> 45 FormalParameter: 46 type: "AppointmentChecker" 47 name: "instance" 48 modifier: "" 49 FormalParameter: 50 type: "MeetingAppointment" 51 name: "meeting" 52 modifier: "" 53 FormalParameter 54 type: "boolean" 55 name: "expected" 56 modifier: "" 57 argumentsofsut: {"meeting"} 58 exceptiontestmethod: TestMethod 59 TestMethod: 60 name: "CheckAppointmentTestThrowingException" 61 invocationofsut: "instance.checkappointment" 62 withexception: false 63 returntype: null 64 testcasesources: {"throwingexceptiontestdata"} 46

55 65 formalparameters: List<FormalParameter> 66 FormalParameter: 67 type: "AppointmentChecker" 68 name: "instance" 69 modifier: "" 70 FormalParameter: 71 type: "MeetingAppointment" 72 name: "meeting" 73 modifier: "" 74 FormalParameter: 75 type: "Class<Throwable>" 76 name: "expected" 77 modifier: "" 78 argumentsofsut: {"meeting"} 3. Xtend: Mit den Informationen die im TestCode-Objekt gespeichert sind, kann nun gezielt Code für das entsprechende Framework erstellt werden. In dieser Arbeit wurde das JUnit 5 Framework [22] benutzt, da es einige praktische Funktionen wie parametrisierte Tests, Anzeigenamen und Quellenauswahl enthält. Für die Codeerzeugung wird Xtend verwendet (siehe Abschnitt 2.2), da dies den Vorteil hat, lesbareren Code zu generieren, da auch Einrückungen direkt übernommen werden und nicht StringBuilder verwendet werden müssen. Jede Test-Klasse besteht im Groben aus vier Blöcken: Header: Alle Metainformationen, wie id (in einem Kommentar), package und imports werden noch oberhalb der tatsächlichen Klasse geschrieben, genauso wie der Anzeigename ("@DisplayName"). Danach folgt die Klasse mit dem vorher definierten Klassennamen. Factories: Als erstes werden alle Factorymethoden, falls vorhanden, als Methoden geschrieben. Der Körper dieser Methoden muss noch vom Benutzer erstellt werden, daher wird dort ein Kommentar mit TODO gesetzt und eine UnsupportedOperationException geworfen, um ihn daran zu erinnern. Test Methoden: Dies ist der Hauptblock der Klasse mit einer oder beiden Testmethoden, falls benötigt. Diese werden als parametrisierte Tests definiert, da dadurch nur eine einzige Methode für viele Testfälle benötigt wird. Dies ermöglicht auch, einen Anzeigenamen für die Ausführung zu definieren, der den Namen, des zu erwartenden Ergebnisses und die Eingabewerte anzeigt, wodurch der Benutzter schneller erkennt, was gerade getestet wird ohne sich die Methode ansehen zu müssen. 47

56 Die reguläre Methode testet, wenn die Methode mit den Testdaten aufgerufen wird, ob das zu erwartende Ergebnis mit dem tatsächlichen Ergebnis übereinstimmt, beziehungsweise bei Methoden ohne Rückgabewert, ob keine Exception geworfen wurde. Die Exception-Methode testet, ob genau die angegebene Exception geworfen wird. Test-Quellen: Schlussendlich werden noch die Test Quellen als Streams mit Argumenten geschrieben. Dabei enthält jedes Argument alle notwendigen Daten eines einzellnen Testfalls, während die Streams nach positiven, negativen und Exception werfenden Test gruppiert sind. Nach der Klasse wird auch noch der komplette Code, Base64-kodiert, angefügt, da dies für die Implementierung des Code Merge notwendig ist. 4. Speichern: Der im letzten Abschnitt generierte Code wird nun in einer Datei gespeichert. Da der Code Merge noch nicht existiert, wird die Klasse jedes mal neu geschrieben. Sie wird in demselben Ordner wie die Originalklasse gespeichert. Diese ist im package definiert. Als Name wird der vorher generierten Klassennamen verwendet, da es in Java Standard ist, dass Klasse und Datei gleich heißen. Listing 20: Generierte Test-Klasse 1 package meetingcalculator; 2 3 import static org.junit.jupiter.api.assertions.assertequals; 4 import static org.junit.jupiter.api.assertions.assertthrows; 5 6 import java.util.stream.stream; 7 8 import org.junit.jupiter.params.provider.arguments; 9 import org.junit.jupiter.api.displayname; 10 import org.junit.jupiter.params.parameterizedtest; 11 import org.junit.jupiter.params.provider.methodsource; import java.lang.exception; 14 Method CheckAppointment") 16 public class CheckAppointmentTest { 17 = "{3} [{index}] expected: ''{2}'' input: ''{0}'', ''{1}''") "negativetestdata"}) 21 public void CheckAppointmentTest(AppointmentChecker instance, MeetingAppointment meeting, boolean expected, String testcasename) throws Exception { 22 boolean actual = instance.checkappointment(meeting); 48

57 23 assertequals(expected, actual); 24 } 25 exception tests") = "{3} [{index}] expected: throw ''{2}'' input: ''{0}'', ''{1}''") 29 public void CheckAppointmentTestThrowingException(AppointmentChecker instance, MeetingAppointment meeting, Class<Throwable> expected, String testcasename) { 30 assertthrows(expected, () -> instance.checkappointment(meeting)); 31 } private static Stream<Arguments> positivetestdata() { 34 return Stream.of( 35 Arguments.of(new AppointmentChecker(new MeetingAppointment[] {new MeetingAppointment(new DateTime(2021, 2, 19, 12, 0), new DateTime (2021, 2, 19, 13, 0)), new MeetingAppointment(new DateTime(2021, 2, 20, 12, 0), new DateTime(2021, 2, 20, 13, 0))}), new MeetingAppointment(new DateTime(2021, 2, 19, 11, 0), new DateTime (2021, 2, 19, 12, 0), "Meeting"), true, "p1: ") 36 ); 37 } private static Stream<Arguments> negativetestdata() { 40 return Stream.of( 41 Arguments.of(new AppointmentChecker(new MeetingAppointment[] {new MeetingAppointment(new DateTime(2021, 2, 19, 12, 0), new DateTime (2021, 2, 19, 13, 0)), new MeetingAppointment(new DateTime(2021, 2, 20, 12, 0), new DateTime(2021, 2, 20, 13, 0))}), new MeetingAppointment(new DateTime(2021, 2, 19, 12, 30), new DateTime (2021, 2, 19, 12, 45), "Check Up"), false, "n2: meeting: occupied") 42 ); 43 } private static Stream<Arguments> throwingexceptiontestdata() { 46 return Stream.of( 47 Arguments.of(new AppointmentChecker(new MeetingAppointment[] {new MeetingAppointment(new DateTime(2021, 2, 19, 12, 0), new DateTime (2021, 2, 19, 13, 0)), new MeetingAppointment(new DateTime(2021, 2, 20, 12, 0), new DateTime(2021, 2, 20, 11, 0))}), new MeetingAppointment(new DateTime(2021, 2, 19, 11, 0), new DateTime (2021, 2, 19, 12, 0), "Meeting"), Exception.class, "n1: instance: invalid"), 48 Arguments.of(new AppointmentChecker(new MeetingAppointment[] {new MeetingAppointment(new DateTime(2021, 2, 19, 12, 0), new DateTime (2021, 2, 19, 13, 0)), new MeetingAppointment(new DateTime(2021, 2, 20, 12, 0), new DateTime(2021, 2, 20, 13, 0))}), new MeetingAppointment(new DateTime(2021, 2, 19, 12, 0), new DateTime (2021, 2, 19, 11, 0)), Exception.class, "n3: meeting: invalid") 49 ); 50 } 49

58 Abbildung 21: Ergebnis der ausgeführten Test Klasse } Mithilfe von JUnit 5 können die Tests dieser Klasse wie herkömmliche JUnit-Tests gestartet werden. Das Ergebnis für das CheckAppointment-Beispiel, das die Testumgebung anzeigt, ist in Abbildung 21 zu sehen. Hier kann man schön erkennen, welche Methode getestet wird. Die untere Test-Methode ist jene, die eine Exception wirft. Jeder Test hat dabei eine eigene Zeile, welche Name und Kommentar, sowie den erwarteten Rückgabewert oder die erwartete Exception anzeigt. Am Ende sind noch die Eingabewerte aufgeführt. Die obere Test-Methode enthält den Test des Normalfalls, wobei auch hier erkennbar ist, welcher Wert zurückgegeben wird und ein eventueller Kommentar, warum dies der Fall ist. In allen Zeilen sieht man auch noch die Eingabewerte, wobei diese vor allem bei primitiven Typen interessant sind. Dass diese Informationen angezeigt werden, ist der zu verdanken. Diese wird so im Code-Generator erstellt, um dem Benutzer möglichst viele Informationen zu liefern, ohne in den Code schauen zu müssen. 4.4 Testmethodik Es wurden viele unterschiedliche Methodensignaturen getestet und es wurde überprüft, ob das TestItem-Objekt gültig ist und der Methodensignatur entspricht. Um eine möglichst große Vielfalt an unterschiedlichen, gültigen Signaturen zu bekommen, wurde Devmate selbst verwendet. Als Repräsentanten für jeden Parameter wurden verschieden Typen als String verwendet (siehe Abbildung 22). Der erste Parameter enthält nur den leeren String und static. Die anderen besitzen drei Äquivalenzklassen: PrimitiveTypes, Arrays und complextypes. Für den Rückgabewert wurde noch der leere String durch void ersetzt. Der letzte Parameter enthält eine eventuelle Exception. Der Test-Generator kann mithilfe dieser Repräsentanten einige Testfälle erstellen, welche verschiedene Kombination der verschiedenen Parameter beinhalten. In Abbildung 23 ist eine Seite der generierten Testfälle zu sehen. 50

59 Abbildung 22: Auszug der Repräsentanten 51

60 Abbildung 23: Eine Seite der generierten Testfälle Abbildung 24: Ergebnisse der Testfälle 52

Programmieren in Java -Eingangstest-

Programmieren in Java -Eingangstest- Programmieren in Java -Eingangstest- Nummer: 1. Studiengang: Informatik B.Sc. Informatik M.Sc. ESE B.Sc. ESE M.Sc. Sonstiges: Fachsemester: Bitte Fragen, die Sie nicht beantworten können unbedingt mit

Mehr

Fachgebiet Softwaretechnik, Heinz Nixdorf Institut, Universität Paderborn. Testen. Tutorial im Rahmen des Software(technik)praktikums SS 2012

Fachgebiet Softwaretechnik, Heinz Nixdorf Institut, Universität Paderborn. Testen. Tutorial im Rahmen des Software(technik)praktikums SS 2012 Testen Tutorial im Rahmen des Software(technik)praktikums SS 2012 Grundlagen (1) Software ist ein fundamentales Element in der Softwarequalitätssicherung Software wird am häufigsten eingesetzt Viele Organisationen

Mehr

Implementieren von Klassen

Implementieren von Klassen Implementieren von Klassen Felder, Methoden, Konstanten Dr. Beatrice Amrhein Überblick Felder/Mitglieder (Field, Member, Member-Variable) o Modifizierer Konstanten Methoden o Modifizierer 2 Felder und

Mehr

Interface. So werden Interfaces gemacht

Interface. So werden Interfaces gemacht Design Ein Interface (=Schnittstelle / Definition) beschreibt, welche Funktionalität eine Implementation nach Aussen anzubieten hat. Die dahinter liegende Algorithmik wird aber der Implementation überlassen.

Mehr

12. Java Klassen. Klassen - Technisch. Beispiel: Erdbebendaten. Klassen - Konzeptuell

12. Java Klassen. Klassen - Technisch. Beispiel: Erdbebendaten. Klassen - Konzeptuell Klassen - Technisch Eine Klasse ist eine Einheit mit einem Namen, die Daten und Funktionalität beinhaltet 12. Java Klassen Klassen, Typen, Objekte, Deklaration, Instanzierung, Konstruktoren, Kapselung,

Mehr

Probeklausur: Programmierung WS04/05

Probeklausur: Programmierung WS04/05 Probeklausur: Programmierung WS04/05 Name: Hinweise zur Bearbeitung Nimm Dir für diese Klausur ausreichend Zeit, und sorge dafür, dass Du nicht gestört wirst. Die Klausur ist für 90 Minuten angesetzt,

Mehr

Enterprise JavaBeans Überblick

Enterprise JavaBeans Überblick Enterprise JavaBeans Überblick 1. Überblick Java EE 5 und Komponententechnologien 2. Einführung Java EE 5 Plattform 3. Enterprise JavaBeans Architektur 4. Ressourcen Management und Primäre Services 5.

Mehr

Objektorientierte Programmierung. Kapitel 22: Aufzählungstypen (Enumeration Types)

Objektorientierte Programmierung. Kapitel 22: Aufzählungstypen (Enumeration Types) Stefan Brass: OOP (Java), 22. Aufzählungstypen 1/20 Objektorientierte Programmierung Kapitel 22: Aufzählungstypen (Enumeration Types) Stefan Brass Martin-Luther-Universität Halle-Wittenberg Wintersemester

Mehr

Languages and Tools for Object-Oriented Development Klausur Wintersemester 2007/2008

Languages and Tools for Object-Oriented Development Klausur Wintersemester 2007/2008 Languages and Tools for Object-Oriented Development Klausur Wintersemester 2007/2008 27. Februar 2008 Institut für Softwaresysteme, TUHH Regeln: 1. Zu dieser Klausur sind keinerlei Hilfsmittel zugelassen.

Mehr

Algorithmen und Datenstrukturen 07

Algorithmen und Datenstrukturen 07 (7. Juni 2012) 1 Besprechung Blatt 6 Fragen 2 Referenzen Referenzsemantik 3 Vererbung Allgemein abstract Interfaces Vererbung in UML 4 Vorbereitung Blatt 7 Anmerkungen Fragen Fragen zu Blatt 6? Referenzsemantik

Mehr

Programmierung Nachklausurtutorium

Programmierung Nachklausurtutorium Programmierung Nachklausurtutorium Laryssa Horn, Tim Engelhardt 20 März 2018 Klassen Wofür wir Klassen brauchen: Definieren ein Bauplan eines Objektes Bauplan enthält Attribute und Methoden Klasse Beispiel

Mehr

Schlussendlich geben wir die Listen aus. Es kommt zu folgender Ausgabe:

Schlussendlich geben wir die Listen aus. Es kommt zu folgender Ausgabe: Musterlösung Übung 7 Aufgabe 1 Sehen wir uns zu allererst das gegebene Forth Programm an: 0 3 new - list constant list1 list1 5 new - list constant list2 list1 6 new - list constant list3 list2 2 new -

Mehr

Aufgabenblatt 4. Aufgabe 3. Aufgabe 1. Aufgabe 2. Prof. Dr. Th. Letschert Algorithmen und Datenstrukturen

Aufgabenblatt 4. Aufgabe 3. Aufgabe 1. Aufgabe 2. Prof. Dr. Th. Letschert Algorithmen und Datenstrukturen Prof. Dr. Th. Letschert Algorithmen und Datenstrukturen Aufgabenblatt 4 Aufgabe 1 1. Erläutern Sie in eigenen Worten die Begriffe Datenstruktur, Datentyp und abstrakter Datentyp. Nutzen Sie das Beispiel

Mehr

Objektorientiertes Programmieren (Java)

Objektorientiertes Programmieren (Java) Grundlagen Objektorientiertes Programmieren (Java) Java folgt gewissen Rechtschreibregeln die Syntax. Diese besagt, dass hinter jeden Befehl ein Semikolon( ; ) stehen muss, damit der Computer weiß, dass

Mehr

Johannes Unterstein - TINF16 - Java - Sommersemester 2017 JAVA. Weiterführende Spracheigenschaften

Johannes Unterstein - TINF16 - Java - Sommersemester 2017 JAVA. Weiterführende Spracheigenschaften JAVA Weiterführende Spracheigenschaften 100 AGENDA Strings Exceptions Enums Generics Lambdas & Methods Bulk-Operations 101 DIE KLASSE STRING Zeichenketten werden in Java als String repräsentiert Wie der

Mehr

Kapitel 9: Klassen und höhere Datentypen. Klassen und höhere. Objekte, Felder, Methoden. Küchlin/Weber: Einführung in die Informatik

Kapitel 9: Klassen und höhere Datentypen. Klassen und höhere. Objekte, Felder, Methoden. Küchlin/Weber: Einführung in die Informatik Klassen und höhere Datentypen Objekte, Felder, Methoden Küchlin/Weber: Einführung in die Informatik Klassen Klasse (class) stellt einen (i.a. benutzerdefinierten) Verbund-Datentyp dar Objekte sind Instanzen

Mehr

Institut für Programmierung und Reaktive Systeme. Java 7. Markus Reschke

Institut für Programmierung und Reaktive Systeme. Java 7. Markus Reschke Institut für Programmierung und Reaktive Systeme Java 7 Markus Reschke 14.10.2014 Vererbung in Java Vererbung ermöglicht es, Klassen zu spezialisieren Wiederverwendung vorhandener Klassen Kindsklasse erhält

Mehr

IT I: Heute. abstrakte Methoden und Klassen. Interfaces. Interfaces List, Set und Collection IT I - VO 7 1

IT I: Heute. abstrakte Methoden und Klassen. Interfaces. Interfaces List, Set und Collection IT I - VO 7 1 IT I: Heute abstrakte Methoden und Klassen Interfaces Interfaces List, Set und Collection 22.11.2018 IT I - VO 7 1 Wissensüberprüfung Überschreiben von Methoden: Aufruf der Methode der Oberklasse ist oft

Mehr

Enterprise JavaBeans Überblick: 8. Test-Driven Development. 8.1 Einleitung 8.2 Beispiel 8.3 Anwendung mit Eclipse und dem JBoss Application Server

Enterprise JavaBeans Überblick: 8. Test-Driven Development. 8.1 Einleitung 8.2 Beispiel 8.3 Anwendung mit Eclipse und dem JBoss Application Server Enterprise JavaBeans Überblick 1. Überblick Komponententechnologien 2. Einführung 3. Enterprise JavaBeans Architektur 4. Ressourcen Management und Primäre Services 5. Java Persistence: Entity Manager 6.

Mehr

Selbststudium OOP6 & ALG1 Auftrag

Selbststudium OOP6 & ALG1 Auftrag Selbststudium OOP6 & ALG1 Auftrag Kapitel 5.2 1. zu bearbeitende Aufgabe: 5.1 done 2. Auf den Seiten 157/158 wird in der Methode start()ein while-loop verwendet. Kreieren Sie ein Code-Fragment mit derselben

Mehr

Klausur: Java (Liste P)

Klausur: Java (Liste P) Klausur: Java (Liste P) SS05 Erlaubte Hilfsmittel: Gebundene! Unterlagen (Skript mit Anmerkungen, eigene Mitschrift) und maximal ein Buch. Bitte keine losen Blätter. Lösung ist auf den Klausurbögen anzufertigen.

Mehr

7. Schnittstellen Grundlagen zu Schnittstellen. 7. Schnittstellen

7. Schnittstellen Grundlagen zu Schnittstellen. 7. Schnittstellen 7. Schnittstellen Grundlagen zu Schnittstellen 7. Schnittstellen Eine Schnittstelle (Interface) ist eine Spezifikation eines Typs in Form eines Typnamens und einer Menge von Methoden, die keine Implementierungen

Mehr

Weitere Beispiele. Beispiel CD-Spieler: Exemplare eines abstrakten Konzepts. 7. Schnittstellen. Schnittstelle: Syntax

Weitere Beispiele. Beispiel CD-Spieler: Exemplare eines abstrakten Konzepts. 7. Schnittstellen. Schnittstelle: Syntax Weitere Beispiele Beispiel CD-Spieler: Exemplare eines abstrakten Konzepts public interface Funktion { boolean istimdefbereich(double x); double wert(double x); String gibbeschreibung(); public interface

Mehr

Vorkurs Informatik WiSe 15/16

Vorkurs Informatik WiSe 15/16 Java 7 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe, 21.10.2015 Technische Universität Braunschweig, IPS Überblick OO in Java Vererbung Abstrakte Klassen und Interfaces 21.10.2015 Dr. Werner Struckmann

Mehr

13. Java Klassen. Lernziele. Klassen - Technisch. Definition: Klassen

13. Java Klassen. Lernziele. Klassen - Technisch. Definition: Klassen Lernziele Sie können eigene Klassen/Datentypen erstellen. Sie verstehen, wie Objekte von Klassen instanziert und verwendet werden. Sie kennen den Begriff der Datenkapselung und können dies anwenden. 13.

Mehr

Übungsblatt Programmierung und Software-Entwicklung Generizität, Interfaces, Listen, Sortieralgorithmen & JUnit

Übungsblatt Programmierung und Software-Entwicklung Generizität, Interfaces, Listen, Sortieralgorithmen & JUnit Übungsblatt Programmierung und Software-Entwicklung Generizität, Interfaces, Listen, Sortieralgorithmen & JUnit Aufgabe : Die allgemeine Object-Liste Gegeben sei folgendes UML-Klassendiagramm: MyObjectList

Mehr

1 Klassen und Objekte

1 Klassen und Objekte 1 Klassen und Objekte Datentyp - Spezifikation des Typs von Datenobjekten Datenstruktur - logische Ordnung von Elementen eines Datentyps - zur (effizienten) Speicherung, Verwaltung, Zugriff - auf die Elemente

Mehr

Institut für Programmierung und Reaktive Systeme. Java 6. Markus Reschke

Institut für Programmierung und Reaktive Systeme. Java 6. Markus Reschke Institut für Programmierung und Reaktive Systeme Java 6 Markus Reschke 13.10.2014 OOP Objekte = Verhalten (durch Methoden) + Daten (durch Attribute) Klassen = Baupläne für Objekte Kapselung von Programmteilen

Mehr

Programmiermethodik 1. Klausur

Programmiermethodik 1. Klausur Programmiermethodik 1. Klausur 27. 6. 2013 Name Matrikelnummer Aufgabe mögliche Punkte erreichte Punkte 1 21 2 20 3 19 4 19 5 21 6 20 Gesamt 120 1 Seite 2 von 18 Aufgabe 1) Objekt-Orientierung und Vererbung

Mehr

OOSE_02E Testen mit BlueJ/JUnit 4

OOSE_02E Testen mit BlueJ/JUnit 4 OOSE_02E Testen mit BlueJ/JUnit 4 Lehrstuhl Softwaretechnologie, Dr. Birgit Demuth Sommersemester 2018 Vorgehen beim Unit-Test allgemein 1. Testfälle ausdenken / Testfalltabellen erstellen 2. Testfälle

Mehr

JUnit. Software-Tests

JUnit. Software-Tests JUnit Software-Tests Übersicht Einleitung JUnit Jia Li Grundlegendes Diana Howey Hendrik Kohrs Praktische Einbindung Benjamin Koch Zili Ye Einleitung in allgemeines Testen Automatische Tests Testen ist

Mehr

Kapitel 9. Programmierkurs. Attribute von Klassen, Methoden und Variablen. 9.1 Attribute von Klassen, Methoden und Variablen

Kapitel 9. Programmierkurs. Attribute von Klassen, Methoden und Variablen. 9.1 Attribute von Klassen, Methoden und Variablen Kapitel 9 Programmierkurs Birgit Engels Anna Schulze Zentrum für Angewandte Informatik Köln Objektorientierte Programmierung Attribute von Klassen, Methoden und Variablen Interfaces WS 07/08 1/ 18 2/ 18

Mehr

Lernteam OOP3 SW Programmieren 1 - H1103 Felix Rohrer

Lernteam OOP3 SW Programmieren 1 - H1103 Felix Rohrer Aufgabe 1: Datentypen und Typecasting Geben Sie das Ergebnis für folgende mathematischen Ausdrücke im entsprechenden Datentyp in Java an. Beachten Sie hierzu die Folie 14 der Präsentation. Hinweis: Bei

Mehr

Teil 5 - Java. Programmstruktur Operatoren Schlüsselwörter Datentypen

Teil 5 - Java. Programmstruktur Operatoren Schlüsselwörter Datentypen Teil 5 - Java Programmstruktur Operatoren Schlüsselwörter Datentypen 1 Kommentare in Java In Java gibt es drei Möglichkeiten zur Kommentierung: // Kommentar Alle Zeichen nach dem // werden ignoriert. für

Mehr

Objekte. Theorieteil. Inhaltsverzeichnis. Begriffe. Programmieren mit Java Modul 5. 1 Modulübersicht 3

Objekte. Theorieteil. Inhaltsverzeichnis. Begriffe. Programmieren mit Java Modul 5. 1 Modulübersicht 3 Programmieren mit Java Modul 5 Objekte Theorieteil Inhaltsverzeichnis 1 Modulübersicht 3 2 Klassen und Objekte 3 2.1 Klassen.................................... 4 2.2 Objektvariablen und Methoden.......................

Mehr

Kapitel 13. Abstrakte Methoden und Interfaces. Fachgebiet Knowledge Engineering Prof. Dr. Johannes Fürnkranz

Kapitel 13. Abstrakte Methoden und Interfaces. Fachgebiet Knowledge Engineering Prof. Dr. Johannes Fürnkranz Kapitel 13 Abstrakte Methoden und Interfaces 13. Abstrakte Klassen und Interfaces 1. Abstrakte Klassen 2. Interfaces und Mehrfachvererbung Folie 12.2 Abstrakte Methoden und Klassen Manchmal macht es überhaupt

Mehr

OOSE4 Testen mit BlueJ/JUnit 4

OOSE4 Testen mit BlueJ/JUnit 4 OOSE4 Testen mit BlueJ/JUnit 4 Lehrstuhl Softwaretechnologie, Dr. Birgit Demuth Sommersemester 2016 Vorgehen beim Unit-Test allgemein 1. Testfälle ausdenken / Testfalltabellen erstellen 2. Testfälle nach

Mehr

Programmieren in Java

Programmieren in Java Einführung in die Objektorientierung Teil 4 Interfaces, innere Klassen und Polymorphie 2 Vererbung im Klassendiagram (Wiederholung) Vererbung repräsentiert eine ist ein Beziehung zwischen Klassen Ware

Mehr

Informatik II Übung 06. Benjamin Hepp 5 April 2017

Informatik II Übung 06. Benjamin Hepp 5 April 2017 Informatik II Übung 06 Benjamin Hepp benjamin.hepp@inf.ethz.ch 5 April 2017 Nachbesprechung U5 5 April 2017 Informatik II - Übung 01 2 Nachbesprechung U5 1. Einfach verkettete Listen Keine Probleme 2.

Mehr

Properties und Proxies

Properties und Proxies g n årà Dr. Winfried Grünewald service@grnwld.de Properties und Proxies Dr. Winfried Grünewald, Stutensee 2011 Version 0.9 2/10 1 Einleitung Die Java Entwicklungsumgebung bietet mit den Properties-Dateien

Mehr

JUnit 4 Tutorial. Wolfgang Stöttinger

JUnit 4 Tutorial. Wolfgang Stöttinger JUnit 4 Tutorial Wolfgang Stöttinger JUnit 4 Tutorial... 1 1 Einführung in JUnit 4... 3 1.1 Wie funktioniert JUnit?... 3 1.2 Annotations... 3 1.2.1 Test Annotation... 3 1.2.2 Before Annotation... 3 1.2.3

Mehr

Wiederholung Sortiert nach Lebenszyklusphase Sortiert nach Testziel Sortiert nach der Methode, um an Testfälle zu kommen

Wiederholung Sortiert nach Lebenszyklusphase Sortiert nach Testziel Sortiert nach der Methode, um an Testfälle zu kommen Testen Wiederholung Sortiert nach Lebenszyklusphase Sortiert nach Testziel Sortiert nach der Methode, um an Testfälle zu kommen JUnit Tests = Komponententests Stress Test White Box Test Integrationstests

Mehr

Das Interface-Konzept am Beispiel der Sprache Java

Das Interface-Konzept am Beispiel der Sprache Java Das Interface-Konzept am Beispiel der Sprache Java Klaus Kusche, November 2013 Inhalt Motivation: Wozu braucht man Interfaces? Interfaces in Java Was spricht gegen die große Lösung? Voraussetzungen Kenntnisse

Mehr

Info B VL 14: Java Collections/Reflections

Info B VL 14: Java Collections/Reflections Info B VL 14: Java Collections/Reflections Objektorientiere Programmierung in Java 2003 Ute Schmid (Vorlesung) Elmar Ludwig (Übung) FB Mathematik/Informatik, Universität Osnabrück Info B VL 14: Java Collections/Reflections

Mehr

pue13 January 28, 2017

pue13 January 28, 2017 pue13 January 28, 2017 1 Aufgabe 1 (Klammern und Anweisungsblöcke) Wie Sie in der Vorlesung gelernt haben, werden Anweisungsblöcke in Java nicht durch Einrückung, sondern mithilfe von geschweiften Klammern

Mehr

Programmieren in Java

Programmieren in Java Programmieren in Java Vorlesung 05: Generics Prof. Dr. Peter Thiemann Albert-Ludwigs-Universität Freiburg, Germany SS 2015 Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 1 / 19 Inhalt Generics

Mehr

II.4.4 Exceptions - 1 -

II.4.4 Exceptions - 1 - n 1. Unterklassen und Vererbung n 2. Abstrakte Klassen und Interfaces n 3. Modularität und Pakete n 4. Ausnahmen (Exceptions) n 5. Generische Datentypen n 6. Collections II.4.4 Exceptions - 1 - Ausnahmen

Mehr

Grundlagen der OO- Programmierung in C#

Grundlagen der OO- Programmierung in C# Grundlagen der OO- Programmierung in C# Technische Grundlagen 1 Dr. Beatrice Amrhein Überblick Visual Studio: Editor und Debugging Die Datentypen Methoden in C# Die Speicherverwaltung 2 Visual Studio 3

Mehr

Einführung in die Programmierung 1

Einführung in die Programmierung 1 Einführung in die Programmierung 1 Einführung (S.2) Einrichten von Eclipse (S.4) Mein Erstes Programm (S.5) Hallo Welt!? Programm Der Mensch (S.11) Klassen (S.12) Einführung Wie Funktioniert Code? Geschriebener

Mehr

JAVA 05: Objektorientierte Konzepte

JAVA 05: Objektorientierte Konzepte Lernkartenkurs JAVA 05: Objektorientierte Konzepte panitz Zusammenfassung Dieser Kurs beschäftigt sich mit Grundkonzepten der objektorientierten Programmierung. Was sind Klassen und Objekte? Wie sehen

Mehr

Vererbung und Polymorphie

Vererbung und Polymorphie Vererbung und Polymorphie Marc Satkowski, Sascha Peukert 29. September 2016 C# Kurs Gliederung 1. Methodenüberladung 2. Vererbung Polymorphie Methoden- & Eigenschaftsüberschreibung Weitere Schlüsselwörter

Mehr

Einstieg in die Informatik mit Java

Einstieg in die Informatik mit Java 1 / 27 Einstieg in die Informatik mit Java Klassen als Datenstrukturen Gerd Bohlender Institut für Angewandte und Numerische Mathematik Gliederung 2 / 27 1 Überblick: Klassen als Datenstruktur 2 Vereinbarung

Mehr

Kapitel 10. Verweise und Referenzen. Fachgebiet Knowledge Engineering Prof. Dr. Johannes Fürnkranz

Kapitel 10. Verweise und Referenzen. Fachgebiet Knowledge Engineering Prof. Dr. Johannes Fürnkranz Kapitel 10 Verweise und Referenzen Inhalt von Kapitel 10 Verweise und Referenzen 10.1 Das Schlüsselwort this Definition Verwendungszweck Klassenmethoden EINSCHUB: Musterlösung zu Übung 4.1 10.2 Objektreferenzen

Mehr

Meta Programming and Reflection in Java

Meta Programming and Reflection in Java Meta Programming and Reflection in Java Overview instanceof operator Java Annotations Java Reflection instanceof operator vergleicht ein Objekt mit einem bestimmten Typ testet ob ein Objekt ist eine Instanz

Mehr

Javakurs 2013 Objektorientierung

Javakurs 2013 Objektorientierung Javakurs 2013 Objektorientierung Objektorientierte Programmierung I Armelle Vérité 7 März 2013 Technische Universität Berlin This work is licensed under the Creative Commons Attribution-ShareAlike 3.0

Mehr

Programmiermethodik 3. Klausur Lösung

Programmiermethodik 3. Klausur Lösung Programmiermethodik 3. Klausur Lösung 9. 1. 2014 Name Matrikelnummer Aufgabe mögliche Punkte erreichte Punkte 1 20 2 16 3 45 4 19 5 20 Gesamt 120 1 Seite 2 von 10 Aufgabe 1) Objekt-Orientierung und Vererbung

Mehr

Umsetzung einer Klassenkarte in einer Programmiersprache

Umsetzung einer Klassenkarte in einer Programmiersprache Klassen in Java Umsetzung einer Klassenkarte in einer Programmiersprache Objektorientierte Programme bestehen (nur) aus Klassendefinitionen In Klassendefinitionen wird die Struktur der Objekte festgelegt,

Mehr

Prüfung Softwareentwicklung II (IB)

Prüfung Softwareentwicklung II (IB) Hochschule für angewandte Wissenschaften München Fakultät für Informatik und Mathematik Studiengruppe IB 2 B, IB 2 C Sommersemester 2013 Prüfung Softwareentwicklung II (IB) Datum : 11.07.2013, 08:30 Uhr

Mehr

ADT: Java Collections und ArrayList

ADT: Java Collections und ArrayList ADT: Java Collections und ArrayList Überblick der Klassen Object File Collections Map List Set ArrayList LinkedList SortedSet HashSet SortedSet Methode ArrayList Klasse I Beschreibung void add(int position,

Mehr

Institut für Programmierung und Reaktive Systeme. Java 2. Markus Reschke

Institut für Programmierung und Reaktive Systeme. Java 2. Markus Reschke Java 2 Markus Reschke 07.10.2014 Datentypen Was wird gespeichert? Wie wird es gespeichert? Was kann man mit Werten eines Datentyps machen (Operationen, Methoden)? Welche Werte gehören zum Datentyp? Wie

Mehr

C++ - Objektorientierte Programmierung Konstruktoren und Destruktoren

C++ - Objektorientierte Programmierung Konstruktoren und Destruktoren C++ - Objektorientierte Programmierung Konstruktoren und Destruktoren hat eine Kantenlänge hat eine Füllfarbe Kantenlänge setzen Füllfarbe lesen Volumen berechnen Leibniz Universität IT Services Anja Aue

Mehr

Klausur Grundlagen der Programmierung

Klausur Grundlagen der Programmierung Klausur Grundlagen der Programmierung Aufgabenstellung: Martin Schultheiß Erreichte Punktzahl: von 60 Note: Allgemeine Hinweise: Schreiben Sie bitte Ihren Namen auf jedes der Blätter Zugelassene Hilfsmittel

Mehr

Programmiertechnik Klassenvariablen & Instantiierung

Programmiertechnik Klassenvariablen & Instantiierung Programmiertechnik Klassenvariablen & Instantiierung Prof. Dr. Oliver Haase Oliver Haase Hochschule Konstanz 1 Klassenvariablen Zur Erinnerung: Klassen bestehen aus Variablen und Methoden; beide zusammen

Mehr

Faulheit professionell: Fertige Datenbehälter. Das Java-Collections-Framework Typsicherheit Generische Klassen

Faulheit professionell: Fertige Datenbehälter. Das Java-Collections-Framework Typsicherheit Generische Klassen Faulheit professionell: Fertige Datenbehälter Das Java-Collections-Framework Typsicherheit Generische Klassen Das Java Collections Framework Grundlegende Interfaces Das Interface List Das Interface List

Mehr

Informatik II Übung 6

Informatik II Übung 6 Informatik II Übung 6 Gruppe 2 Carina Fuss cfuss@student.ethz.ch 11.4.2018 Carina Fuss 11.4.2018 1 Übung 6 Nachbesprechung Übung 5 Objektorientierung Vererbung, Polymorphie, abstrakte Klassen, Interfaces,

Mehr

Heute. Nachbetrachtung Wissensüberprüfung. Sortieren Interface Comparable TreeSet Sortieren von Arrays: Arrays.sort() 3.12.

Heute. Nachbetrachtung Wissensüberprüfung. Sortieren Interface Comparable TreeSet Sortieren von Arrays: Arrays.sort() 3.12. Heute Nachbetrachtung Wissensüberprüfung Sortieren Interface Comparable TreeSet Sortieren von Arrays: Arrays.sort() 3.12.2015 IT I - VO 9 1 Organisatorisches Zwischentest findet am 16.12. von 17:30 bis

Mehr

Programmierprojekt: So0ware Tests. Anne6e Bieniusa Sommersemester 2017

Programmierprojekt: So0ware Tests. Anne6e Bieniusa Sommersemester 2017 Programmierprojekt: So0ware Tests Anne6e Bieniusa Sommersemester 2017 Testen Kernfrage: Erfüllt die So0ware ihre Anforderungen / SpezifikaGon? FunkGonale Anforderungen Korrekte Ergebnisse bei Berechnungen

Mehr

Objektorientierung. Klassen und Objekte. Dr. Beatrice Amrhein

Objektorientierung. Klassen und Objekte. Dr. Beatrice Amrhein Objektorientierung Klassen und Objekte Dr. Beatrice Amrhein Überblick Konzepte der Objektorientierten Programmierung Klassen und Objekte o Implementierung von Klassen o Verwendung von Objekten 2 Konzepte

Mehr

Javakurs FSS Lehrstuhl Stuckenschmidt. Tag 3 - Objektorientierung

Javakurs FSS Lehrstuhl Stuckenschmidt. Tag 3 - Objektorientierung Javakurs FSS 2012 Lehrstuhl Stuckenschmidt Tag 3 - Objektorientierung Warum Objektorientierung Daten und Funktionen möglichst eng koppeln und nach außen kapseln Komplexität der Software besser modellieren

Mehr

Programmieren in Java

Programmieren in Java Programmieren in Java Vorlesung 10: Ein Interpreter für While Prof. Dr. Peter Thiemann Albert-Ludwigs-Universität Freiburg, Germany SS 2015 Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 1

Mehr

Ausnahmen. Exceptions. Definition Ausnahmen erzeugen Ausnahmen abfangen Ausnahmen weiterleiten. Dr. Beatrice Amrhein

Ausnahmen. Exceptions. Definition Ausnahmen erzeugen Ausnahmen abfangen Ausnahmen weiterleiten. Dr. Beatrice Amrhein Ausnahmen Exceptions Definition Ausnahmen erzeugen Ausnahmen abfangen Ausnahmen weiterleiten Dr. Beatrice Amrhein Definition 2 Definition: Ausnahme (Exception) In C# werden Fehler, die zur Laufzeit im

Mehr

Übungen zum Bioinformatik-Tutorium. Blatt 3

Übungen zum Bioinformatik-Tutorium. Blatt 3 Institut für Informatik Wintersemester 2018/19 Praktische Informatik und Bioinformatik Prof. Dr. Ralf Zimmer Übungen zum Bioinformatik-Tutorium Blatt 3 Termin: Dienstag, 6.11.2018, 11 Uhr 1. Hello World

Mehr

Java Tools JDK. IDEs. Downloads. Eclipse. IntelliJ. NetBeans. Java SE 8 Java SE 8 Documentation

Java Tools JDK. IDEs.  Downloads. Eclipse. IntelliJ. NetBeans. Java SE 8 Java SE 8 Documentation Java Tools JDK http://www.oracle.com/technetwork/java/javase/ Downloads IDEs Java SE 8 Java SE 8 Documentation Eclipse http://www.eclipse.org IntelliJ http://www.jetbrains.com/idea/ NetBeans https://netbeans.org/

Mehr

Vorkurs Informatik WiSe 16/17

Vorkurs Informatik WiSe 16/17 Java Ausdrücke und Variablen Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe, 05.10.2016 Technische Universität Braunschweig, IPS Überblick Ausdrücke, Datentypen und Variablen Kontrollstrukturen 05.10.2016

Mehr

C# - Einführung in die Programmiersprache Methoden. Leibniz Universität IT Services

C# - Einführung in die Programmiersprache Methoden. Leibniz Universität IT Services C# - Einführung in die Programmiersprache Methoden Leibniz Universität IT Services 02.07.12 Methoden... sind Subroutinen in einer Klasse. können einen Wert an den Aufrufer zurückgeben. verändern die Eigenschaften

Mehr

14. Java Klassen. Klassen (Java) vs. Records (Pascal) Klassen - Konzeptuell. Klassen - Technisch

14. Java Klassen. Klassen (Java) vs. Records (Pascal) Klassen - Konzeptuell. Klassen - Technisch Klassen (Java) vs. Records (Pascal) 14. Java Klassen Klassen, Typen, Objekte, Deklaration, Instanzierung, Konstruktoren, statische Felder und Methoden, Datenkapselung Pascal RECORDs in Pascal sind reine

Mehr

Mock-Objekte. Universität Karlsruhe (TH) Fakultät für Informatik Lehrstuhl für Programmiersysteme. Forschungsuniversität gegründet 1825

Mock-Objekte. Universität Karlsruhe (TH) Fakultät für Informatik Lehrstuhl für Programmiersysteme. Forschungsuniversität gegründet 1825 Universität Karlsruhe (TH) Forschungsuniversität gegründet 1825 Mock-Objekte Verschiedene Testhelfer Ein Stummel (engl. stub) ist ein nur rudimentär implementierter Teil der Software und dient als Platzhalter

Mehr

IT I: Heute. Nachbetrachtung Wissensüberprüfung. Einführung Vererbung. Roboter in becker.robots. Filialenbelieferung 4.11.

IT I: Heute. Nachbetrachtung Wissensüberprüfung. Einführung Vererbung. Roboter in becker.robots. Filialenbelieferung 4.11. IT I: Heute Nachbetrachtung Wissensüberprüfung Einführung Vererbung Roboter in becker.robots Filialenbelieferung 4.11.2014 IT I - VO 4 1 Organisatorisches Tutorium am Mi, 12.11. schon um 11 Uhr (bis 12:30).

Mehr

Einstieg in die Informatik mit Java

Einstieg in die Informatik mit Java Vorlesung vom 18.4.07, Grundlagen Übersicht 1 Kommentare 2 Bezeichner für Klassen, Methoden, Variablen 3 White Space Zeichen 4 Wortsymbole 5 Interpunktionszeichen 6 Operatoren 7 import Anweisungen 8 Form

Mehr

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 16/17. Kapitel 13. Listen. Listen 1

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 16/17. Kapitel 13. Listen. Listen 1 Kapitel 13 Listen Listen 1 Ziele Implementierungen für Listen kennenlernen Einfach verkettete und doppelt verkettete Listen verstehen Listen-Implementierungen in der Java-Bibliothek kennenlernen Durch

Mehr

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 15/16. Kapitel 12. Listen. Listen 1

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 15/16. Kapitel 12. Listen. Listen 1 Kapitel 12 Listen Listen 1 Ziele Implementierungen für Listen kennenlernen Einfach verkettete und doppelt verkettete Listen verstehen Listen-Implementierungen in der Java-Bibliothek kennenlernen Durch

Mehr

1 Abstrakte Klassen, finale Klassen und Interfaces

1 Abstrakte Klassen, finale Klassen und Interfaces 1 Abstrakte Klassen, finale Klassen und Interfaces Eine abstrakte Objekt-Methode ist eine Methode, für die keine Implementierung bereit gestellt wird. Eine Klasse, die abstrakte Objekt-Methoden enthält,

Mehr

13. Java Klassen. Klassen, Typen, Objekte, Deklaration, Instanzierung, Konstruktoren, Kapselung, statische Felder und Methoden

13. Java Klassen. Klassen, Typen, Objekte, Deklaration, Instanzierung, Konstruktoren, Kapselung, statische Felder und Methoden 378 Lernziele Sie können eigene Klassen/Datentypen erstellen. Sie verstehen, wie Objekte von Klassen instanziert und verwendet werden. Sie kennen den Begriff der Datenkapselung und können dies anwenden.

Mehr

Systematisches Testen

Systematisches Testen Systematisches Testen SEP 136 Unit Testing Objektorientierte Entwicklung Entwicklung von vielen unabhängigen Einheiten (Klassen, Methoden), aus denen das Gesamtprogramm zusammengesetzt wird. Ziel: Wenn

Mehr

Repetitorium Informatik (Java)

Repetitorium Informatik (Java) Repetitorium Informatik (Java) Tag 6 Lehrstuhl für Informatik 2 (Programmiersysteme) Übersicht 1 Klassen und Objekte Objektorientierung Begrifflichkeiten Deklaration von Klassen Instanzmethoden/-variablen

Mehr

Einstieg in die Informatik mit Java

Einstieg in die Informatik mit Java 1 / 22 Einstieg in die Informatik mit Java Generics Gerd Bohlender Institut für Angewandte und Numerische Mathematik Gliederung 2 / 22 1 Überblick Generics 2 Generische Klassen 3 Generische Methoden 4

Mehr

IT I: Heute. Nachbetrachtung Wissensüberprüfungen. Einführung Vererbung. Roboter in becker.robots. falls Zeit: Scheduling 8.11.

IT I: Heute. Nachbetrachtung Wissensüberprüfungen. Einführung Vererbung. Roboter in becker.robots. falls Zeit: Scheduling 8.11. IT I: Heute Nachbetrachtung Wissensüberprüfungen Einführung Vererbung Roboter in becker.robots falls Zeit: Scheduling 8.11.2016 IT I - VO 5 1 Organisatorisches VO nächste Woche im Peter-Tunner-HS! Tutorium

Mehr

12 Abstrakte Klassen, finale Klassen und Interfaces

12 Abstrakte Klassen, finale Klassen und Interfaces 12 Abstrakte Klassen, finale Klassen und Interfaces Eine abstrakte Objekt-Methode ist eine Methode, für die keine Implementierung bereit gestellt wird. Eine Klasse, die abstrakte Objekt-Methoden enthält,

Mehr

Einführung in die Programmierung

Einführung in die Programmierung Technische Universität München WS 2003/2004 Institut für Informatik Prof. Dr. Christoph Zenger Semestralklausur Einführung in die Programmierung Semestralklausur Java (Lösungsvorschlag) 1 Die Klasse ArrayList

Mehr

Informatik II Übung 7 Gruppe 7

Informatik II Übung 7 Gruppe 7 Informatik II Übung 7 Gruppe 7 Leyna Sadamori leyna.sadamori@inf.ethz.ch Informatik II Übung 7 Leyna Sadamori 10. April 2014 1 Administratives Nächste Übung fällt leider aus! Bitte eine andere Übung besuchen.

Mehr

Sichtbarkeiten, Klassenmember und -methoden

Sichtbarkeiten, Klassenmember und -methoden Sichtbarkeiten, Klassenmember und -methoden Prof. Dr.-Ing. Thomas Schwotzer 11. November 2017 1 Einführung Wir haben uns mit Klassen und Objekten beschäftigt. Wir wissen nun, dass Objekte anhand von Klassen

Mehr

Objektorientierung. Marc Satkowski 20. November C# Kurs

Objektorientierung. Marc Satkowski 20. November C# Kurs Objektorientierung Marc Satkowski 20. November 2016 C# Kurs Gliederung 1. Weiterführende Verzweigungen Tertiäre-Verzweigung switch case 2. Schleifen Zählschleife (for) break & continue 3. Objektorientierung

Mehr

Organisatorisches. Neue Übungsblätter: Nur mehr elektronisch? Abgabe Di, , 14 Uhr bis Do, , 8Uhr

Organisatorisches. Neue Übungsblätter: Nur mehr elektronisch? Abgabe Di, , 14 Uhr bis Do, , 8Uhr Organisatorisches Neue Übungsblätter: Nur mehr elektronisch? Abgabe Di, 14.10., 14 Uhr bis Do, 23.10., 8Uhr. 14.10.2014 IT I - VO 1 1 IT I: Heute Wiederholung CuP ctd: this Arrays, ArrayLists Schleifen:

Mehr

Kapitel 5: Interfaces

Kapitel 5: Interfaces Liste P: Programmieren mit Java WS 2001/2002 Prof. Dr. V. Turau FH Wiesbaden Kapitel 5: Interfaces Folie 82 : Einleitung Betrachtet man die Programmierleistung für ein Produkt über einen längeren Zeitraum,

Mehr

Tag 8 Repetitorium Informatik (Java)

Tag 8 Repetitorium Informatik (Java) Tag 8 Repetitorium Informatik (Java) Dozent: Michael Baer Lehrstuhl für Informatik 2 (Programmiersysteme) Friedrich-Alexander-Universität Erlangen-Nürnberg Wintersemester 2017/2018 Informatik-Repetitorium

Mehr

Softwaretechnik WS 16/17. Übungsblatt 01

Softwaretechnik WS 16/17. Übungsblatt 01 Softwaretechnik WS 16/17 Übungsblatt 01 Was ist eine Klasse? Definition der Object Management Group: A class describes a set of objects that share the same specifications of features, constraints, and

Mehr

Bachelorprüfung: Objektorientierte Softwareentwicklung

Bachelorprüfung: Objektorientierte Softwareentwicklung Bachelorprüfung: Objektorientierte Softwareentwicklung WS17/18 Erlaubte Hilfsmittel: keine Jeder Griff zu einem elektronischen Gerät (z.b. Smartphone) wird als Täuschungsversuch gewertet. Lösung ist auf

Mehr