211 lines
9.3 KiB
Plaintext
211 lines
9.3 KiB
Plaintext
:source-highlighter: coderay
|
||
:icons: font
|
||
:experimental:
|
||
:!sectnums:
|
||
:imagesdir: ./images/
|
||
:handout: ./code/
|
||
|
||
:logo: IT.PROG2 -
|
||
ifdef::backend-html5[]
|
||
:logo: image:PROG2-300x300.png[IT.PROG2,100,100,role=right,fit=none,position=top right]
|
||
endif::[]
|
||
ifdef::backend-pdf[]
|
||
:logo:
|
||
endif::[]
|
||
ifdef::env-github[]
|
||
:tip-caption: :bulb:
|
||
:note-caption: :information_source:
|
||
:important-caption: :heavy_exclamation_mark:
|
||
:caution-caption: :fire:
|
||
:warning-caption: :warning:
|
||
endif::[]
|
||
|
||
// references
|
||
:mockito-home: http://mockito.org/[Mockito Homepage]
|
||
:mockito-docs: http://mockito.github.io/mockito/docs/current/org/mockito/Mockito.html[Mockito Dokumentation]
|
||
:mockito-annotations: https://www.baeldung.com/mockito-annotations[Konkrete Beispiele mit Mockito]
|
||
:planet-wissen-herz: https://www.planet-wissen.de/video-das-herz--wie-funktioniert-es-100.html[Planet Wissen]
|
||
:maven-central: https://search.maven.org/search?q=a:mockito-core[MavenCentral]
|
||
|
||
|
||
= {logo} Praktikum Mock-Testing
|
||
|
||
== Einleitung
|
||
|
||
Ziele dieses Praktikums sind:
|
||
|
||
* Anwenden von erweiterten Testverfahren (Mocks, Spys)
|
||
* Übung des Umgangs mit Mockito
|
||
|
||
=== Voraussetzungen
|
||
|
||
* Vorlesung Mock-Testing
|
||
|
||
=== Tooling
|
||
* Installiertes JDK 17+.
|
||
* Gradle 7.4+
|
||
* Mockito ab Version 2.
|
||
|
||
=== Struktur
|
||
Das Praktikum enthält verschiedene Arten von Aufgaben, die wie folgt gekennzeichnet sind:
|
||
|
||
[TU] – Theoretische Übung::
|
||
Dient der Repetition bzw. Vertiefung des Stoffes aus der Vorlesung und als Vorbereitung für die nachfolgenden Übungen.
|
||
|
||
[PU] – Praktische Übung::
|
||
Übungsaufgaben zur praktischen Vertiefung von Teilaspekten des behandelten Themas.
|
||
|
||
[PA] – Pflichtaufgabe::
|
||
Übergreifende Aufgabe zum Abschluss. Das Lösen dieser Aufgaben ist Pflicht. Sie muss bis zum definierten Zeitpunkt abgegeben werden, wird bewertet und ist Teil der Vornote.
|
||
|
||
|
||
=== Zeit und Bewertung
|
||
Für das Praktikum stehen zwei Wochen in den Praktikumslektionen und im Selbststudium zur Verfügung.
|
||
|
||
Je nach Kenntniss- und Erfahrungsstufe benötigen Sie mehr oder weniger Zeit.
|
||
Nutzen Sie die Gelegenheit, den Stoff zu vertiefen, auszuprobieren, Fragen zu stellen und Lösungen zu diskutieren (Intensive-Track).
|
||
|
||
Falls Sie das Thema schon beherrschen, müssen Sie nur die Pflichtaufgaben lösen und bis zum angegebenen Zeitpunkt abgeben (Fast-Track).
|
||
|
||
Sie können die Lösungen der Textaufgaben in diesem Praktikum direkt in den Java-Files als Kommentar hinzufügen - oder als Markdown-File neben den Java-Files.
|
||
|
||
=== Referenzen
|
||
|
||
* link:{handout}[Praktikumsverzeichnis – Quellcode, Projektstruktur]
|
||
* link:{mockito-home}
|
||
* link:{mockito-docs}
|
||
* link:{mockito-annotations}
|
||
|
||
:sectnums:
|
||
:sectnumlevels: 2
|
||
// Beginn des Aufgabenblocks
|
||
|
||
== Herz
|
||
Das menschliche Herz ist ein lebenswichtiges und kompliziertes Organ.
|
||
Nur, wenn seine einzelnen "Bauteile" richtig koordiniert werden, kann es eine ausreichende Blutversorgung unseres Körpers gewährleisten.
|
||
|
||
Da es beim Mocking um das Testen des Verhaltens eines Objekts geht, bietet sich das Herz als Beispiel an.
|
||
Darum simulieren wir in dieser Aufgabe ein menschliches Herz.
|
||
Eine kurze Erklärung der Funktionsweise des Herzens gibt es auf link:{planet-wissen-herz}.
|
||
|
||
Einige Fakten über das Herz, die bei dieser Aufgabe helfen können -
|
||
im Projekt werden englische Begriffe verwendet, die Sie in Klammern finden:
|
||
|
||
* Das Herz (Heart) besteht aus zwei Hälften.
|
||
* Jede Herzhälfte (Half) hat einen Vorhof (Atrium) und eine Herzkammer (Ventricle).
|
||
Vorhöfe sammeln Blut, Herzkammern pressen es in den Körper.
|
||
* Zwei Phasen wechseln sich jeweils ab.
|
||
** Anspannungsphase: Systole
|
||
** Entspannungsphase: Diastole
|
||
* Die Herzklappen sind eine Art Rücklaufventile, es gibt 2 verschiedene:
|
||
** 2 Segelklappen (AtrioventricularValve): verhindern, dass Blut in der Systole in den Vorhof zurückfliesst.
|
||
** 2 Taschenklappen (SemilunarValve): verhindern, dass in der Diastole Blut ins Herz zurückfliesst.
|
||
|
||
image:Heart_diagram-en.svg.png[pdfwidth=75%, width=600px]
|
||
|
||
=== Ablauf des Herzschlags
|
||
|
||
==== Diastole – Blut sammelt sich im Vorhof ("atrium")
|
||
|
||
* Segelklappen ("atrioventricular valves") öffnen
|
||
* Taschenklappen ("semilunar valves") schliessen
|
||
* Vorhöfe ("atria") entspannen
|
||
* Herzkammern ("ventricle") entspannen
|
||
* Warten auf Systole
|
||
|
||
==== Systole
|
||
|
||
* Segelklappen schliessen
|
||
* Taschenklappen öffnen
|
||
* Herzkammern kontrahieren
|
||
* Vorhöfe kontrahieren
|
||
* Warten auf Diastole
|
||
|
||
Es gibt die folgenden Klassen im Projekt:
|
||
|
||
image:heartbeat_classdiagram.png[pdfwidth=75%, width=600px]
|
||
|
||
Darüber hinaus gibt es eine Klasse `HeartTest`, die bereits mehrere Tests implementiert.
|
||
|
||
Stubs sind nicht sehr intelligent und daher kann man häufig nur oberflächlich mit Stubs testen.
|
||
Sie sollen mit Hilfe von Mock-Objekten die Tests noch gründlicher gestalten.
|
||
|
||
Die Abhängigkeit für Mockito ist bereits für Sie in build.gradle erfasst worden.
|
||
Studieren Sie kurz in diesem File, wie das gemacht wurde.
|
||
Informationen dazu finden Sie auf der link:{mockito-home} und auf link:{maven-central}.
|
||
|
||
Studieren bzw. überfliegen Sie bei dieser Gelegenheit auch gerade die link:{mockito-docs}.
|
||
|
||
|
||
== Aufgaben
|
||
|
||
=== Einführung in Mockito [PU]
|
||
[loweralpha]
|
||
. Studieren Sie die Testmethoden `HeartTest::testValveStatus()` und `HeartTest::testExecuteHartBeatErrorBehaviour()`.
|
||
Dort wird *ein Teil* des Verhaltens des Herzens getestet.
|
||
|
||
. Implementieren Sie die Methoden `Heart::executeDiastole()`, `Heart::executeSystole()` und `Heart::executeHeartBeat()` sodass die bestehenden Tests durchlaufen und das oben beschriebene Verhalten des Herzens modelliert wird.
|
||
|
||
. (optional) Ein echtes Herz hat eine Schlagfrequenz.
|
||
Implementieren Sie, dass das Herz nach jeder Systole pausiert.
|
||
Sie können z. B. den aktuellen Thread 1000 ms lang anhalten mit
|
||
+
|
||
[source, Java]
|
||
----
|
||
try {
|
||
Thread.currentThread().sleep(1000);
|
||
} catch (InterruptedException e) {
|
||
e.printStackTrace();
|
||
}
|
||
----
|
||
|
||
=== Fragen zu Testing [TU]
|
||
[loweralpha]
|
||
. Testing kann in zwei unterschiedliche Strategien aufgeteilt werden.
|
||
Zum einen gibt es White-Box Testing und zum zweiten Black-Box Testing.
|
||
Was für Java Libraries gibt es um diese zwei Strategien zu testen?
|
||
Wann wenden Sie welche Strategie an?
|
||
|
||
. Das Erstellen von guten automatisierten Unit-Tests kann manchmal schwierig umzusetzen sein.
|
||
Was ist der Hauptgrund dafür? Wie können Sie dieses Problem entschärfen?
|
||
|
||
. Der Testfokus war bisher auf der Klasse `Heart`.
|
||
Testen Sie jetzt die Klasse `Half`. Wo verwenden Sie Stubbing, wo Mocking?
|
||
|
||
=== Vorbedingungen, Exceptions und Callback-Funktionen [PA]
|
||
[loweralpha]
|
||
. Testen Sie, dass beim Ausführen der Diastole und Systole alle Herzklappen in der richtigen Reihenfolge geöffnet und geschlossen werden.
|
||
Implementieren Sie dafür die Methode `HeartTest::testValvesBehavior()` und benutzen Sie die von Mockito bereitgestellte Klasse `InOrder`. +
|
||
Testen Sie auch, dass keine Methode unnötig oft aufgerufen wird (mit der Methode `Inorder::verifyNoMoreInteractions()`). +
|
||
Benutzen Sie mindestens einmal die statische Methode `mock()` und einmal die Annotation `@Mock` von Mockito.
|
||
|
||
. Die vorhandene Implementation des Testfalls `HeartTest::testExecuteHartBeatErrorBehaviour()` verwendet keine Mock-Objekte für die linke und rechte Herzhälfte.
|
||
Implementieren Sie die Testmethode `HeartTest::testExecuteHartBeatErrorBehaviourWithStubbing()` analog zur bestehenden Variante, aber diesmal setzen Sie entsprechende Mock-Objekte für die Herzhälften ein.
|
||
+
|
||
TIP: Für das Stubbing werden Sie die `doThrow`- Methode von Mockito benötigen.
|
||
Mit Stubbing ist die Konfiguration von Ihrem Mock-Objekt gemeint.
|
||
|
||
. Die bestehende Implementierung hat einen ungenügenden Exception-Mechanismus.
|
||
Beispielsweise führt die Herzhälfte (`Half`) ihre Methoden aus, auch wenn die notwendigen Vorbedingungen (d.h., die Klappenstellungen von `SemilunarValve` und `AtrioVentricularValve`)
|
||
nicht gelten. +
|
||
Beheben Sie dieses Problem, indem Sie in `Heart::executeDiastole()` und `Heart::executeSystole()` eine `InvalidValvePositionException` werfen,
|
||
falls die notwendigen Vorbedingungen nicht in der korrekten Position (offen, geschlossen) sind. +
|
||
Erstellen Sie zwei Methoden `testDiastoleException()` und `testSystoleException()` und setzen Sie Mocking und Stubbing ein, um diesen Exception-Mechanismus zu testen.
|
||
|
||
. Die Klasse Pacemaker ist eine Implementation für einen Herzschrittmacher.
|
||
Es ist eine unvollständige Implementation, reduziert auf das Wesentliche für den Inhalt des Praktikums.
|
||
Ihre Aufgabe ist es, die Methode `Pacemaker::setHeartRate` mit zwei vorgegeben Testfällen zu testen. +
|
||
Implementieren Sie Test-Methoden `PacemakerTest::testSetHeartRateRejectsFrequenciesOutOfRange` und `PacemakerTest::testSetHeartRateAppliesFrequenciesInsideRange`. +
|
||
Die beiden Testfälle prüfen die Methode `Pacemaker::setHeartRate` darauf, ob sie korrekt reagiert, wenn das Herz die gewünschte Frequenz im einen Fall anwenden und im anderen Fall nicht anwenden kann.
|
||
In diesem Szenario ist die Klasse `Pacemaker` die Class-Under-Test und die Klasse `Heart` eine Abhängigkeit für `Pacemaker`. +
|
||
Verwenden Sie für die Klasse `Heart` ein entsprechendes Mock-Objekt und stubben Sie das Verhalten gemäss der Spezifikation von der Methode `Heart::setHeartRate()`.
|
||
Eine Voraussetzung ist, dass Sie für beide Testfälle dasselbe Mock-Objekt mit demselben Stubbing verwenden können.
|
||
Die Callback-Methode wird Ihnen dabei eine Hilfe sein.
|
||
|
||
|
||
== Abschluss
|
||
Stellen Sie sicher, dass die Tests der Pflichtaufgabe mittels `gradlew test` gestartet werden können und pushen Sie die Lösung vor der Deadline in Ihr Abgaberepository.
|
||
|
||
|
||
|