65
Komponenten – WS 2014/15 – Teil 8/Mocks 15.11.14 1 Komponenten-basierte Entwicklung Teil 8: Einführung in Mocks

Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 15.11.14 1

Komponenten-basierte Entwicklung

Teil 8: Einführung in Mocks

Page 2: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 2

Literatur und Web

[8-1] Vigenschow, Uwe: Objektorientiertes Testen und Testautomatisierung in der Praxis. dpunkt, 2005

[8-2] Westphal, Frank: Testgetriebene Entwicklung mit JUnit & FIT. dpunkt, 2006

[8-3] Link, Johannes: Softwaretests mit JUnit. 2. Auflage, dpunkt, 2005

[8-4] Tamm, Michael: JUnit-Profiwissen. dpunkt, 2013

[8-5] Ullenboom, C.: Java 7 - Mehr als eine Insel: Das Handbuch zu den Java SE-Bibliotheken, Gallileo Computing, 2011

Page 3: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 3

Übersicht

• Unit-Tests

• Abhängigkeiten

• Arbeiten mit Stubs

• Arbeiten mit Mocks

Page 4: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 4

Bedingungen für sinnvolles Testen

• Reproduzierbarkeit eines Testfalls

• Klar definierte Umgebung

• Zusammenfassung von– Daten in Dateien

– Zuständen von Datenbanken

– Erfassung des Outputs

zu einem Testfall.

• Es wird immer nur ein Aspekt getestet.

• Abdeckung des Codes:– Alle Pfade (Minimalbedingung)

– Alle möglichen Pfadkombinationen

müssen mindestens einmal durchlaufen werden

• Pfad = Codesequenz ohne Möglichkeit einer Verzweigung innerhalb einer Routine

Page 5: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 5

Unit- und Integrations-Test

• Ein Unit-Test liegt nur dann vor, wenn ein kleines in sich abgeschlossenes Codestück sinnvoll getestet wird.

• Üblicherweise sind diese Codestücke– Einzelne Klassen in OO-Sprachen, z.B. Java, C#, C++

– Funktionen/Routinen, z.B. C

– Module, z.B. Modula, ADA (erste Version)

• Diese Codestücke sind dann die Units.

• Ein Integrationstest liegt vor, wenn mehrere Units zu einem Komplex zusammengefasst getestet werden.

• Es wird empfohlen, mit Unit-Tests zu beginnen und dann Integrationstest durchzuführen, wenn die betreffenden Units in Ordnung sind.

Siehe dazu

• http://de.wikibooks.org/wiki/Softwaretechnik:_Unit-Testing

• http://en.wikipedia.org/wiki/Unit_testing

• http://de.wikipedia.org/wiki/Modultest

Page 6: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 6

Abhängigkeiten I

• Abhängigkeit = Dependency = Gerichtete Relation zwischen zwei Codestücken A und B, wobei die Korrektheit von A von der Korrektheit von B abhängt, in dem Sinne, dass A fehlerhaft ist, wenn B fehlerhaft ist. Dann hängt A von B ab.

• Aufgrund von Rekursion kann es auch eine gegenseitige Abhängigkeit geben.

• Statt von Abhängigkeit kann auch von der Benutzt-Relation gesprochen werden.

• Abhängigkeiten können wie folgt realisiert werden:– A ruft B auf (z.B. Call, Methodenaufruf)

– B produziert Daten für A (z.B. Daten, Messwerte)

– B ist der Manager für A (z.B. Starten, Stoppen, Scheduling)

– A erbt von B

– B interpretiert die Software von A (z.B. CPU, Virtuelle Maschine)

– B übersetzt die Software von A (z.B. Compiler, Assembler)

• Wir beschäftigen uns hier nur mit den Aufruf-Abhängigkeiten.

Page 7: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 7

Beispiel

• Erstellt mit dem dependency-Walkerhttp://www.dependencywalker.com/

• http://www.heise.de/download/dependency-walker.html

Die Abhängigkeiten desJava-Compiler javac aufeinem x64-Win7 System

Page 8: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 8

Abhängigkeiten II

• http://en.wikipedia.org/wiki/Coupling_(computer_programming)

• http://de.wikipedia.org/wiki/Dependency_Injection

Siehe dazu

Klasse AKlasse A

Klasse B

Call

Klasse AKlasse A

Stub B

Call

Wie könnte ein Unit-Test der Klasse A aussehen?

Klasse B ist vollständigrealisiert

Klasse B ist nur für den Testrealisiert (Simulation)

Page 9: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 9

Stubs und Mocks I

• Stub = Codestück zur Bereitstellung von Schnittstellen, z.B. Schnittstellencode bei CORBA

• Stub = Codestück zur Simulation einer Schnittstelle/UnitDiese Variante des Begriffs ist hier gemeint

• Ein Stub-Objekt – oder kurz Stub – – ist eine verkürzte Implementierung eines anderen Objekts,

– liefert vorgefertigte Antworten/Reaktionen.

• http://de.wikipedia.org/wiki/Stub_(Programmierung)

• http://de.wikipedia.org/wiki/Mock-Objekt

• http://de.wikipedia.org/wiki/Mocking_Framework

Siehe dazu

Page 10: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 10

Stubs und Mocks II

• Mock = Attrappe = Stub mit Monitormöglichkeiten

Darunter wird verstanden, dass die Aufrufe des zu testenden Objekts samt Parametern aufgezeichnet werden, um nach dem Test auf Korrektheit geprüft zu werden.

• Mock Objekte – kurz Mocks – werden fast immer mit Bibliotheken bzw. Frameworks realisiert.

• Beispiele dafür sind– EasyMock

– MockObjects

– PowerMock

– Mockito

Page 11: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 11

Vorgehen I

Klasse AKlasse A

TestRunner

Klasse Atest

Stub B

Call

CUT benutzt nur Sprache undderen Standard-Libraries

Call

Klasse AKlasse A

TestRunner

Klasse Atest

Call

Call

Call

CUT benutzt nebenSprache dieKlasse B

Page 12: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 12

Vorgehen II

• CUT = Class Under Test oder Component Under Test

• SUT = System Under Test

• DOC = Depended On Component

• Zu einem Testfall (also einem Test eines Aspekts) gehören:

Stub B

Klasse ACUT

Klasse CUTtest

Call

Call

Die Implementierungensind eng gekoppelt undsollten daher immerzusammen bleiben

SUT

DOC

Page 13: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 13

Beispiel 1: Schnick-Schnack-Schnuck I

• Es soll ein Spielsimulator für das Spiel Schnick-Schnack-Schnuck oder Schere-Stein-Papier realisiert werden.

• Vorgehen:– Es beginnt mit einem Klassenentwurf.

– Dann werden Interfaces definiert.

– Darauf basierend eine unvollständige Klasse, die dann schrittweise getestet wird.

http://de.wikipedia.org/wiki/Schere,_Stein,_Papier

Page 14: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 14

Beispiel 1: Schnick-Schnack-Schnuck II

• Es wird entschieden, keine enum-Klasse zu implementieren, stattdessen wird mit Konstanten gearbeitet.

SiSaSu

Oponent

MyChoice

Call

Call

DiceInterface

Moves

States

implements

extends

implements

implementsHauptprogramm

Spielgegner

Zufallsgenerator

Page 15: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 15

Die Interfaces I

public interface States { final int tokenPaper = 0; final int tokenStone = 1; final int tokenScissors= 2; final int resultUndecided = 0; final int resultOponentWins = 1; final int resultHumanWins = 2;}

public interface Moves extends States { public int makeMove(int num); public int matchResult();}

erbt

Spielzüge

Spielergebnisse

Spielzug machen

Ergebnis berechnen

Page 16: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 16

Die Interfaces II

• Wir nehmen nun an, dass die Klasse MyChoice bereits implementiert und getestet ist.

• Das geschah mit den vorher vorgestellten Methoden und Verfahren.

public interface DiceInterface { public int rollDice();}

import java.util.Random;

public class MyChoice implements DiceInterface { @Override public int rollDice() { Random rand = new Random(); return rand.nextInt(3); }}

generiert Zahlenzwischen 0 und 2

Page 17: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 17

Leerschema der Klasse Oponent

public class Oponent implements Moves, States { Oponent() { } @Override public int makeMove(int humanTurn) { } @Override public int matchResult() { }}

Page 18: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 18

Leerschema der Klasse OponentTest I

import static de.htw_berlin.f4.kbe.States.*;

public class OponentTest { Oponent opo; public OponentTest() {} @Before public void setUp() { opo= new Oponent(); } @After public void tearDown() { opo= null; }

@Test public void testPaper() { int choiceOfOponent= opo.makeMove(tokenPaper); int result= opo.matchResult(); assertEquals("Paper:Paper",resultUndecided,result); }}

Page 19: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 19

Leerschema der Klasse OponentTest II

• Damit wir in der Testklasse und auch im Hauptprogramm die Konstanten für die Zustände benutzen können, müssen wir diese importieren (über ein Static Import).

• Jetzt wird auch klar, warum wir ein extra Interface mit den Konstanten benötigen (States): diese werden an verschiedenen Stellen benutzt.

• Hinweis: Die Trennung in zwei Interfaces ist eine Implemen-tierungsentscheidung, die auch anders hätte getroffen werden können, z.B. die Konstanten in das Interface Moves zu tun.

Nun, wenn wir dann die Klasse Oponent wie folgt implementieren,bekommen wir 2/3 aller Fälle einen roten Balken.

Page 20: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 20

Klasse Oponent - Teil1

public class Oponent implements Moves { private int humanTurn; private int myTurn; private MyChoice dice; Oponent() { humanTurn= -1; myTurn = -1; dice= new MyChoice(); } @Override public int makeMove(int humanTurn) { this.humanTurn= humanTurn; myTurn= dice.rollDice(); return myTurn; }

Der Grund für den roten Balken liegt in der zufälligen Zahl durchMyChoice() - dies müsste geändert werden – geht aber nicht automatisch.

FesteVerdrahtung

Page 21: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 21

Klasse Oponent – Teil2 - Spiellogik

@Override public int matchResult() { boolean humanWins= false; if(myTurn==humanTurn) { return resultUndecided; } switch(humanTurn) { case tokenPaper: humanWins= (myTurn==tokenStone); break; case tokenStone: humanWins= (myTurn==tokenScissors); break; case tokenScissors: humanWins= (myTurn==tokenPaper); break; } return humanWins ? resultHumanWins : resultOponentWins; }}

Page 22: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 22

Ein Stub muss her I

• Die Benutzung einer anderen Klasse wird Dependency (Abhängigkeit) genannt.

• Wenn die Abhängigkeit von Außen gesteuert werden kann, wird dies Dependency Injection genannt.

• Hier erfolgt dies mit Hilfe des Konstruktors; es bleibt aber das Problem.

@Before public void setUp() { opo= new Oponent(new MyChoice());}

private DiceInterface dice;

Oponent(DiceInterface dice) { humanTurn= -1; myTurn = -1; this.dice= dice;}

Änderung in derKlasse Oponent(Konstruktor)

Änderung in derKlasse OponentTest(setUp())

Page 23: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 23

Ein Stub muss her II

• Nun gibt es grün.

• Und wir können alle Testfälle definieren, die eine Wahl von Papier seitens der Maschine erfordern.

import static de.htw_berlin.f4.kbe.States.*;

public class StubPaper implements DiceInterface { @Override public int rollDice() { return tokenPaper; }}

@Before public void setUp() { opo= new Oponent(new StubPaper()); }

Das ist der Stub,der immer nurPapier wählt.

Das ist der Teilder Testklassemit dem Stub.

Page 24: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 24

Ein Stub muss her III

public class OponentTest {... @Before public void setUp() { opo= new Oponent(new StubPaper()); }... @Test public void testPaper() { int choiceOfOponent= opo.makeMove(tokenPaper); int result= opo.matchResult(); assertEquals("Paper:Paper",resultUndecided,result); choiceOfOponent= opo.makeMove(tokenStone); result= opo.matchResult(); assertEquals("Paper:Stone",resultOponentWins,result); choiceOfOponent= opo.makeMove(tokenScissors); result= opo.matchResult(); assertEquals("Paper:Scissors",resultHumanWins,result);}}

Es werden alle drei Varianten, wenn die Maschine Papier wählt, getestet.

Page 25: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 25

Ein Stub muss her IV

• Das Ganze wiederholt sich noch 2x mit jeweils einer Testklasse.

• Also 3x Oponent-Test und 3x Stub sind erforderlich.

• Dies lässt sich in einer Suite zusammenfassen:

package de.htw_berlin.f4.kbe;

import org.junit.runners.Suite;import org.junit.runner.RunWith;

@RunWith(Suite.class)@Suite.SuiteClasses({ OponentTest.class, Oponent2Test.class, Oponent3Test.class,})public class OponentSuite {}

Page 26: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 26

Es läuft, aber...

• für die einzelnen Varianten jeweils manuell Stubs erzeugt werden.

• die Testklassen beim Aufbau des Fixture sehr ähnlich sind.

es ist recht unbefriedigend, da

Besser wäre es, wenn die Stubs automatisch generiert werden,und das machen Mock-Bibliotheken.

Im folgenden wird das Framework Mockito vorgestellt.

Page 27: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 27

Mocks am Beispiel Mockito I - Installation

• http://mvnrepository.com/artifact/org.mockito/mockito-all/1.9.5

<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version></dependency>

• http://de.wikipedia.org/wiki/Mockito

• https://code.google.com/p/mockito/

• https://code.google.com/p/mockito/wiki/FAQ

• http://mockito.github.io/mockito/docs/current/org/mockito/Mockito.html

Maven

Allgemeine Information

Page 28: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 28

Mocks am Beispiel Mockito II - netbeans

• Jar-Datei herunter laden, z.B. Version 1.9.5

• In Installationsordner kopieren, z.B. dort, wo auch maven ist

• In das Projekt bringen:

• Fertig!

Page 29: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 29

Mocks Strategie

• Erwartungen definieren – welche Funktionen was tun

• Code ausführen und dabei Antworten aufzeichnen

• Reaktionen prüfen

• Aufzeichnung prüfen

Vier Phasen/Abschnitte

• Arrange

• Act

• Assert and Verify

Test werden am besten nach dem AAA-Schema geschrieben

Page 30: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 30

SiSaSu – noch einmal mit Mockito I

public class Mocks02Test { public Mocks02Test() { }

@Test public void testPaper() { // Arange DiceInterface dice= mock(MyChoice.class); when(dice.rollDice()).thenReturn(tokenPaper); Oponent cut= new Oponent(dice);

// Act int choiceOfOponent= cut.makeMove(tokenPaper); int result= cut.matchResult();

// Assert and Verify assertEquals("Paper:Paper",resultUndecided,result); verify(dice,times(1)).rollDice(); }}

Der Aufbau dieser Testroutine arbeitet nicht mehr mit @before bzw. @after.

Page 31: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 31

Erläuterungen I

• mock() erzeugt dynamisch (also zur Laufzeit) eine neue Klasse mit dem Interface des übergebenen Klassendeskriptors.

• Ein Klassendeskriptor wird per Reflektion erzeugt, hier durch das „Pseudo-Attribut" .class.

• Die Mock-Klasse (dice) wird mit dem Interface deklariert, um auszudrücken, dass nur gegen dieses Interface getestet wird.

DiceInterface dice= mock(MyChoice.class);

Page 32: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 32

Erläuterungen II

when(dice.rollDice()).thenReturn(tokenPaper);

• Das ist eine Definition des Verhaltens des Mock-Objekts dice.

• rollDice() gibt den Wert tokenPaper zurück.

• Von dieser Angabe kann es beliebig viele Spezifikationen geben.

verify(dice,times(1)).rollDice();

• Hier wird die Aufzeichnung geprüft.

• rollDice() soll nur ein einziges Mal (times(1)) aufgerufen worden sein.

Bedingung Aktion

Page 33: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 33

Fluent Interfaces I

• Mit Punkt verknüpfte Ketten von Methoden-Aufrufen werden Fluent Interfaces genannt.

• Diese sind sehr beliebt, weil sie sehr kompakt sind.

• Implementiert werden sie, indem am Ende der Methode immer return this programmiert wird.

• Wenn die Namen der Methoden sinnvoll gewählt sind, entsteht eine „neue Sprache"; diese Idee führt dann zu den DSL, den Domain Specific Languages.

Object.methode(...).methode(...).methode(...) usw.

• http://de.wikipedia.org/wiki/Fluent_Interface

• http://martinfowler.com/bliki/FluentInterface.html

Siehe

Page 34: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 34

Fluent Interfaces II - Law of Demeter

• Fluent Interfaces verletzen das „Law of Demeter" (LoD):

Objekte sollen nur mit Objekten ihrer unmittelbaren Umgebung „kommunizieren", d.h. es soll immer eine lose Kopplung zwischen Komponenten/Klassen bestehen.

• Konkret: Eine Methode meth der Klasse C soll nur– klasseneigene Methoden

– Methoden der Parameter vom meth-Aufruf

– Mit C assoziierte Objekte, auch aus der Vererbung

– Methoden selbst erzeugter Objekte

aufrufen bzw. benutzen bzw. eine Abhängigkeit eingehen.

• Ziel: bessere Verständlichkeit und Wartbarkeit

• http://de.wikipedia.org/wiki/Gesetz_von_Demeter

• http://en.wikipedia.org/wiki/Law_of_Demeter

Siehe

Kritik

Page 35: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 35

SiSaSu – noch einmal mit Mockito II

package de.htw_berlin.f4.kbe;

import static de.htw_berlin.f4.kbe.States.*;import static org.mockito.Mockito.*;import org.junit.Test;import static org.junit.Assert.*;

Der fehlende Testklassenkopf

verify(dice,times(1)).rollDice();

verify(dice,times(2)).rollDice();

Page 36: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 36

SiSaSu – noch einmal mit Mockito III

@Test public void testPaper() { int choiceOfOponent, result; DiceInterface dice= mock(MyChoice.class); when(dice.rollDice()).thenReturn(tokenPaper); Oponent cut= new Oponent(dice); choiceOfOponent= cut.makeMove(tokenPaper); result= cut.matchResult(); assertEquals("Paper:Paper",resultUndecided,result); choiceOfOponent= cut.makeMove(tokenStone); result= cut.matchResult(); assertEquals("Paper:Stone",resultOponentWins,result); choiceOfOponent= cut.makeMove(tokenScissors); result= cut.matchResult(); assertEquals("Paper:Scissors",resultHumanWins,result); verify(dice,times(3)).rollDice();}

So, unddas 3x inleichtenVariationen

Page 37: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 37

SiSaSu – noch einmal mit Mockito IV

private DiceInterface dice;private Oponent cut;

private void computerChoice(int token) { dice= mock(MyChoice.class); when(dice.rollDice()).thenReturn(token); cut= new Oponent(dice);}private void humanChoiceResult(int humanToken, String msg, int estimate) { int choiceOfOponent= cut.makeMove(humanToken); int result= cut.matchResult(); assertEquals(msg,estimate,result);}

• Der gemeinsame Teil wird in zwei eigene private(!) Routinen herausgezogen.

• Beide kommunizieren über private globale Variablen (nicht schön, aber einfach).

• Dadurch reduziert sich die Testzeilenzahl erheblich.

Page 38: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 38

SiSaSu – noch einmal mit Mockito V

Die Tests sind nun kompakter, aber auch etwas schwerer lesbar.

@Test public void testPaper() { computerChoice(tokenPaper); humanChoiceResult(tokenPaper, "Paper:Paper", resultUndecided); humanChoiceResult(tokenStone, "Paper:Stone", resultOponentWins); humanChoiceResult(tokenScissors,"Paper:Scissors",resultHumanWins); verify(dice,times(3)).rollDice();}

@Test public void testStone() { computerChoice(tokenStone); humanChoiceResult(tokenStone, "Stone:Stone", resultUndecided); humanChoiceResult(tokenScissors,"Stone:Scissors",resultOponentWins); humanChoiceResult(tokenPaper, "Stone:Paper", resultHumanWins); verify(dice,times(3)).rollDice();}

Page 39: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 39

DRY und Refactoring

• Refactoring = Verfahren der Reorganisation von Code mit den folgenden Zielen:– Bessere Verständlichkeit

– Bessere Wartbarkeit durch Abstraktion

• Refactoring hat nicht das Ziel der Optimierung von Code oder Laufzeit.• Siehe: http://www.ssw.uni-

linz.ac.at/Teaching/Lectures/Sem/2002/reports/Stelzmueller/index.html

• Das andere Prinzip heißt Dont Repeat Yourself (DRY).

• DRY-Prinzip = Vermeidung von duplizierten Code (entstanden durch cut&paste) und von sehr ähnlichem Code

• Ein Implementieren nach dem DRY-Prinzip führt zu denselben Zielen wie das Refactoring.

• Siehe: http://de.wikipedia.org/wiki/Don't_repeat_yourself

Page 40: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 40

(Bad) Code smells – schlechter Code I

• Code Smells = Anzeichen von schlecht strukturierten, unverständlichen Code

• Hier wurden Konstanten innerhalb eines Interfaces definiert. Das ist ein Bad Code Smell.

• Siehe: http://wickedsource.org/2009/02/24/code-smell-constants-interfaces/

• Siehe:– http://de.wikipedia.org/wiki/Smell_(Programmierung)

– http://c2.com/cgi/wiki?CodeSmell

Page 41: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 41

(Bad) Code smells – schlechter Code II

Die Konstanten gehören zur Schnittstelle; sie sind integraler Bestandteil; das ändert sich auch nicht nach dem Befolgen der Empfehlungen: – Ein Auslagerung in eine Klasse, von der die Konstanten geerbt werden,

bringt nichts, da Mehrfachvererbungen nicht möglich sind.

– Am besten ist die Benutzung zweier enum-Klassen, aber das macht wegen der grausamen Realisierung von Enums in Java alles komplizierter.

public interface States { final int tokenPaper = 0; final int tokenStone = 1; final int tokenScissors= 2; final int resultUndecided = 0; final int resultOponentWins = 1; final int resultHumanWins = 2;}

Böse, böse!

Typisch C-Programmierer!

Es gibt aber Argumente dafür:

Page 42: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 42

Ein zweites komplexeres Beispiel I

• Es soll ein UPN-Taschenrechner mit den Grundrechenarten implementiert werden.

• UPN = Umgekehrte Polnische Notation

• Beispiel: "2" "3" "4" "+" "*" = 2*(3+4) = 14

• Entwurf:

Klasse AKlasse FixedLengthStack

Klasse UPN

Call

Hierfür wirdspäter einMock gebaut.

Page 43: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 43

Ein zweites komplexeres Beispiel II - Maven

(1)

(3)

(2)

Etwas schneller – ohne das Herunterladender Archetypenbibliothek: POM-Project

Page 44: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 44

Ein zweites komplexeres Beispiel III - Maven

• JUnit 4.11

• maven-jar-plugin – mit richtigem Name für Startklasse

• exec-maven-plugin – mit richtigem Name für Startklasse

• Mockito:

<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version></dependency>

Page 45: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 45

Vorgehen nach Test Driven Development (TDD)

• Rahmen der Klasse FixedLengthStack schreiben

• Testfälle realisieren

• Klasse implementieren public class FixedLengthStack { String field[]; int top; FixedLengthStack(int size) {

} public void push(String obj) { } public String pop() { return null; }}

public class FixedLengthStackTest { public FixedLengthStackTest() { } FixedLengthStack stack; @Before public void setUp() { stack= new FixedLengthStack(3); } @After public void tearDown() { stack= null; } @Test public void test01() { String ret; stack.push("abc"); ret= stack.pop(); assertEquals("1 Element -->","abc",ret);}}

Page 46: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 46

Klasse FixedLengthStackTest I

...@Test public void test1Element() { String ret; try { stack.push("abc"); ret= stack.pop(); assertEquals("1 Element -->","abc",ret); } catch (StackOverflowException | StackUnderflowException ex) { ex.printStackTrace(); fail("unexpected exception occurred"); }}...

Nach diesem Schema werden 2 und 3 Elemente bei einer maximalenLänge von 3 getestet.

Kommentar

Erwartet

Berechnet

Page 47: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 47

Klasse FixedLengthStackTest II

@Test public void testUnderflow() { String ret; try { ret= stack.pop(); fail("expected StackUnderflowException missed"); } catch (StackUnderflowException ex) { }}

@Test public void testOverflow() { try { stack.push("abc"); stack.push("def"); stack.push("hig"); stack.push("ZZZ"); fail("expected StackOverflowException missed"); } catch (StackOverflowException ex) { }}

So sehen Tests aus, die eineException erwarten

Page 48: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 48

Klasse FixedLengthStack - Implementierung

public class FixedLengthStack { String field[]; int top; FixedLengthStack(int size) { field= new String[size]; top= -1; } public void push(String obj) throws StackOverflowException { if((top+1)>=field.length) { throw new StackOverflowException("push: Overflow"); } field[++top]= obj; } public String pop() throws StackUnderflowException { if(top<0) { throw new StackUnderflowException("pop: Underflow"); } return field[top--]; }}

Neuralgische Punkte!

Page 49: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 49

Klasse UPN - Rahmen

public class UPN { FixedLengthStack stack; UPN(FixedLengthStack stack) { this.stack= stack; } private int executeOp(String op, int left, int right) throws IllegalFormedExpressionException { return 0; } public int compute(String expression[]) throws IllegalFormedExpressionException { return 0; }}

public class IllegalFormedExpressionException extends Exception { public IllegalFormedExpressionException() { } public IllegalFormedExpressionException(String msg) { super(msg); }}

Dependency

Injection

Page 50: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 50

Klasse UPNMockTest I

import static org.mockito.Mockito.*;import org.junit.*;import static org.junit.Assert.*;import org.mockito.InOrder;

public class UPNMockTest { public UPNMockTest() { } UPN computer; FixedLengthStack stack; @Before public void setUp() { stack= mock(FixedLengthStack.class); computer= new UPN(stack); } @After public void tearDown() { computer= null; }

Injection

Page 51: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 51

Klasse UPNMockTest II – Erste Version

@Test public void testAddition() { String expression[]= {"3","4","+"}; try { doNothing().when(stack).push("3"); doNothing().when(stack).push("4"); when(stack.pop()).thenReturn("4").thenReturn("3"); } catch (StackOverflowException | StackUnderflowException ex) {} try { int result= computer.compute(expression); assertEquals("3+4 -->",7,result); } catch (IllegalFormedExpressionException ex) { fail("unexpected exception occurred"); } try { InOrder inOrder = inOrder(stack); inOrder.verify(stack).push("3"); inOrder.verify(stack).push("4"); inOrder.verify(stack,times(2)).pop(); verifyZeroInteractions(stack); } catch (StackOverflowException | StackUnderflowException ex) {}}

Erwartungen

Prüfungen

Page 52: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 52

Einfache dyadische Operationen I

@Test public void testAddition() { String expression[]= {"3","4","+"}; mockProlog2(expression,"7"); try { int result= computer.compute(expression); assertEquals("3+4 -->",7,result); } catch (IllegalFormedExpressionException ex) { fail("unexpected exception occurred"); } mockEpilog2(expression);}

Nach diesem Schema lassen sich auch die anderen dreiGrundrechenarten testen.Da es viele Wiederholungen gibt, werden diese in zweiRoutinen ausgelagert: mockProlog2() und mockEpilog2()

Page 53: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 53

Einfache dyadische Operationen II

private void mockProlog2(String[] expr, String result) { try { doNothing().when(stack).push(expr[0]); doNothing().when(stack).push(expr[1]); when(stack.pop()).thenReturn(expr[1]) .thenReturn(expr[0]) .thenReturn(result); doNothing().when(stack).push(anyString()); } catch (StackOverflowException | StackUnderflowException ex) {}}

Beispiel: String expression[]= {"3","4","+"};

• Es werden die Reaktionen der simulierten Klasse definiert.

• Wenn unterschiedliche Resultate geliefert werden sollen, ist das Fluent-Interface zu benutzen.

Erwartungen

Page 54: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 54

Erläuterungen I

doNothing().when(stack).push(expr[0]);

Hier wird eine void-Routine simuliert. Da keine Daten in derSimulation verwendet werden, wird auch nichts gemacht.

when(stack.pop()).thenReturn(expr[1]) .thenReturn(expr[0]) .thenReturn(result);

Hier wird festgelegt, in welcher Reihenfolge eine Funktion (pop)welche Rückgabewerte liefert.

when(stack.pop()).thenReturn(expr[1]);when(stack.pop()).thenReturn(expr[0]);when(stack.pop()).thenReturn(result);

Dies bewirkt etwas anderes: Für jeden Aufruf von pop() ohne Parameter wird result geliefert.Die vorherigen Werte werden nicht beachtet.

Page 55: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 55

Erläuterungen II

doNothing().when(stack).push(anyString());

anyString() bedeutet, dass jeder Stringwert als Parametergemeint ist, d.h. es wird mindestens ein Aufruf von push(...)erwartet.Die ersten Aufrufe dazu sind wegen dieser Zeile redundant; siesollten aber trotzdem zum Verständnis geschrieben werden.

} catch (StackOverflowException | StackUnderflowException ex) {}

Das ist eine Verkürzung aus Java7: Die beiden Exceptions werdenmit Oder verknüpft.Dies ist dann erforderlich, wenn dieselbe Behandlung erfolgen soll(siehe DRY).

Page 56: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 56

Einfache dyadische Operationen III

private void mockEpilog2(String[] expr) { try { InOrder inOrder= inOrder(stack); inOrder.verify(stack).push(expr[0]); inOrder.verify(stack).push(expr[1]); inOrder.verify(stack,times(2)).pop(); inOrder.verify(stack).push(anyString()); inOrder.verify(stack,times(1)).pop(); verifyZeroInteractions(stack); } catch (StackOverflowException | StackUnderflowException ex) {}}

Prüfungen

• Hier wird nun die exakte Reihenfolge der Aufrufe vonStack-Operationen geprüft.

• Daher geht der interne Algorithmus der zu testende Klasse in die Testfallspezifikation bzw. in die Simulation ein.

• Das wird dann Grey-Test genannt.

Page 57: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 57

Erläuterungen

InOrder inOrder= inOrder(stack);inOrder.verify(stack).push(expr[0]);inOrder.verify(stack).push(expr[1]);

Über das inOrder-Objekt wird die Reihenfolge, nicht nur die bloßeExistenz eines Aufrufs geprüft.

verifyZeroInteractions(stack);

Damit wird geprüft, ob noch weitere Aufrufe statt gefundenhaben. Haben sie das, gibt es ein Test-Fail.

verify(stack).push(expr[0]);verify(stack).push(expr[1]);

Hier nur die bloße Existenz der aufgeführten Aufrufe geprüft.

Page 58: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 58

Test auf die Division durch 0 I

@Test public void testDivisionBy0() { String expression[]= {"42","0","/"}; try { doNothing().when(stack).push("42"); doNothing().when(stack).push("0"); when(stack.pop()).thenReturn("0").thenReturn("42"); } catch (StackOverflowException | StackUnderflowException ex) {} try { int result= computer.compute(expression); fail("expected IllegalFormedExpressionException missed"); } catch (IllegalFormedExpressionException ex) {} try { InOrder inOrder = inOrder(stack); inOrder.verify(stack).push("42"); inOrder.verify(stack).push("0"); inOrder.verify(stack,times(2)).pop(); verifyZeroInteractions(stack); } catch (StackOverflowException | StackUnderflowException ex) {}}

Page 59: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 59

Test auf die Division durch 0 II

• Das ist eine verkürzte Version der vorherigen Tests.

• Ohne Verkürzung gibt es ein Test-Fail bei verifyZeroInteractions().

Page 60: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 60

Test auf falsche Syntax I

@Test public void testIllFormed3() { String expression[]= {"+","42","7"}; try { doThrow(new StackUnderflowException()).when(stack).pop(); } catch (StackUnderflowException ex) {} try { int result= computer.compute(expression); fail("expected IllegalFormedExpressionException missed"); } catch (IllegalFormedExpressionException ex) {} try { InOrder inOrder = inOrder(stack); inOrder.verify(stack).pop(); verifyZeroInteractions(stack); } catch (StackUnderflowException ex) {}}

Page 61: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 61

Test auf falsche Syntax II

doThrow(new StackUnderflowException()).when(stack).pop();

Statt doNothing() kann auch mit doThrow() eine Exceptiongeworfen werden.

Page 62: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 62

Vergleich Integrationstest – Mocks I

@Test public void testMultiplication() { String expression[]= {"3","4","*"}; mockProlog2(expression,"12"); try { int result= computer.compute(expression); assertEquals("3*4 -->",12,result); } catch (IllegalFormedExpressionException ex) { fail("unexpected exception occurred"); } mockEpilog2(expression);}

Version mit Mocks

Page 63: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 63

Vergleich Integrationstest – Mocks II

@Test public void testMultiplication() { String expression[]= {"3","4","*"}; try { int result= computer.compute(expression); assertEquals("3*4 -->",12,result); } catch (IllegalFormedExpressionException ex) { fail("unexpected exception occurred"); }}

Version ohne Mocks

Viel kürzer!

Page 64: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 64

Nachteile von Mocks

• Viel höherer Aufwand als mit Integrationstests.Im vorgestellten Beispiel hat die – zu testende Klasse 63 Zeilen

– simulierte Klasse 21 Zeilen,

– Simulationsklasse mit Tests (Mock) 180 Zeilen

– Testklasse ohne Mock 102 Zeilen

Und: es wurde noch nicht einmal alles Notwendige getestet.

• Selbst ausgereifte Bibliotheken wie Mockito führen nicht zu leicht lesbaren, eingängigen Tests.

• Die Pflege von Mocks ist bei Weiterentwicklungen genauso wichtig wie die der eigentlichen Klassen.

• Testklassen gehören zum eigentlichen Code und müssen dieselben Standards erfüllen.

Page 65: Komponenten-basierte Entwicklung Teil 8: Einführung in Mockswi.f4.htw-berlin.de/users/messer/LV/AI-KBE-WS14/Folien/KBE-08/08-KBE... · Komponenten – WS 2014/15 – Teil 8/Mocks

Komponenten – WS 2014/15 – Teil 8/Mocks 65

Nach dieser Anstrengung etwas Entspannung...