+ All Categories
Home > Documents > Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein...

Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein...

Date post: 02-Nov-2019
Category:
Upload: others
View: 0 times
Download: 0 times
Share this document with a friend
6
javamagazin 11 | 2016 magazin JAVA Mag www.javamagazin.de Ausgabe 11.2016 Programminfos ab Seite 35! Java | Architektur | Software-Innovation AUTOMATISIERTES TESTEN © iStockphoto.com/RomoloTavani Lassen Sie die Software für sich arbeiten JavaFX auf dem Raspberry Pi S. 106 Web-Apps mit Angular 2 S. 84 Logmanagement mit Graylog S. 26
Transcript
Page 1: Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein Testframework, das bereits seit 2008 entwickelt wird [1]. Es ist somit kein komplett neues

javamagazin 11 | 2016

magazinJAVA

Mag

www.javamagazin.de Ausgabe 11.2016

Programminfos

ab Seite 35!

Java | Architektur | Software-Innovation

AUTOMATISIERTES

TESTEN

© iS

tock

phot

o.co

m/R

omol

oTav

ani

Lassen Sie die Software

für sich arbeiten

JavaFX auf dem Raspberry Pi S. 106

Web-Apps mit Angular 2 S. 84

Logmanagement mit Graylog S. 26

Page 2: Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein Testframework, das bereits seit 2008 entwickelt wird [1]. Es ist somit kein komplett neues

javamagazin 11 | 20162 www.JAXenter.de

AgileSonderdruck

© Software & Support Media GmbH

von Mario-Leander Reimer

Bei Spock handelt es sich um ein Testframework, das bereits seit 2008 entwickelt wird [1]. Es ist somit kein komplett neues Framework mehr. Spock kombiniert die Stärken und guten Ansätze vieler altbekannter Frame-works, wie JUnit, JBehave, Mockito oder Hamrest, in einem einzigen Framework. So bringt das Framework bereits etliche eingebaute Funktionen mit, für die man bisher separate Bibliotheken benötigt hat.

Im Kern setzt Spock auf JUnit auf. Das ist eine gute Wahl, denn Spock integriert sich damit reibungslos in die gängige Entwickler-Tool-Chain im JVM-Umfeld. Es stehen Erweiterungen für IDEs wie IntelliJ oder Eclipse bereit. Die Ausführung der Tests übernehmen wie ge-wohnt die Plug-ins des bevorzugten Build-Tools, und auch CI-Server kommen mit Spock gut zurecht.

Die Syntax von Spock ist reduziert und ausdrucks-stark. Das liegt vor allem an der Verwendung von Groo-vy, das durch seine Sprachfeatures dazu beiträgt, sich auf das Wesentliche im Test konzentrieren zu können. Entwickler, die bisher noch keine Berührungspunkte mit Groovy hatten, können aber beruhigt sein. Der Wech-sel von Java nach Groovy ist in nur wenigen Stunden erfolgt. Danach ist man mindestens genauso produktiv wie mit einem Java-basierten Testframework.

Die Spock Groovy DSL gibt die möglichen Strukturen der Tests klar vor, sie folgt dabei im Wesentlichen einer given-when-then-Notation, wie man sie aus dem Behavi-our-driven Development (BDD) kennt. Spock stellt den korrekten Testauf-bau sicher und prüft die korrekte Reihenfolge der einzelnen Phasen. So ist es mit Spock nicht möglich, einen Test zu schreiben,

der keine einzige Assertion enthält. In Abbildung 1 sind die unterstützten Phasen und Blocks dargestellt.

Die erste Außenmission mit SpockUm Spock in einem Projekt zu verwenden, müssen le-diglich einige wenige Dependencies über das bevorzugte Build-Tool hinzugefügt werden (Listing 1). Die Spock Core Dependency wird zwingend benötigt, die anderen Dependencies sind optional.

Ein Spock-Test leitet immer von der Klasse spock.lang.Specification ab. Die Testmethoden werden in Spock mit einem String durch einen Satz in natürlicher Sprache be-nannt. Der Rumpf ist strukturiert, er enthält die Blöcke für das Set-up (Abb. 1), die Interaktion und die Prüfung. Listing 2 zeigt beispielhaft einen einfachen Test.

Interaction-based Tests mit SpockGute Unit-Tests zeichnen sich unter anderem dadurch aus, dass die Testsubjekte in Isolation getestet werden. Bei komplexen Komponenten mit Abhängigkeiten auf andere Komponenten ist dies aber nicht ohne Weiteres möglich. Man behilft sich hier oft, indem man die benö-tigten Kollaborateure durch vorprogrammierte Testdou-bles ersetzt. Bekannte Frameworks im JUnit-Umfeld sind hierzu Mockito oder jMock. Spock benötigt hierfür keine separaten Bibliotheken. Es unterstützt von Haus aus drei verschiedene Arten von Testdoubles: Stubs, Mocks und Spies. Stubs sind einfache Doubles, die lediglich vorpro-grammierte Antworten liefern. Mocks ermöglichen zu-sätzlich die Prüfung aller Aufrufe ihrer Methoden. Spies eignen sich zum Mitschneiden der Aufrufe einer konkre-ten Klasse, ohne dabei das Verhalten zu verändern.

Listing  3 zeigt exemplarisch die Verwendung eines Mocks. In der Set-up-Phase wird zunächst ein Greeting Mock erzeugt und an das Testsubjekt übergeben. Da-nach folgt wie gewohnt die Interaktionsphase. In der Verifikationsphase zeigt sich dann die volle Eleganz von Spock. Die Prüfung sowohl der erwarteten Anzahl an Aufrufen des Mocks als auch die Definition der vorpro-grammierten Antworten lässt sich mit Spock in nur ei-ner Zeile Code ausdrücken. Zu beachten ist außerdem Abb. 1: Blocks und Phasen eines Spock-Tests

Next-Generation-Enterprise-Tests mit Spock

Test long and prosper! In diesem Artikel machen wir uns auf in die unendlichen Weiten der testgetriebenen Entwicklung. Lange war es ruhig in den Reihen der Enterprise-Testframeworks. Die Be-satzung bestehend aus JUnit, Hamcrest und Mockito hat sich als De-facto-Standard für Unit- und Integrationstests etabliert. Doch mit dem Spock Framework kommt nun ein neues Teammitglied an Bord, das alle Testdisziplinen gleichermaßen gut beherrscht.

Page 3: Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein Testframework, das bereits seit 2008 entwickelt wird [1]. Es ist somit kein komplett neues

javamagazin 11 | 2016 3www.JAXenter.de

AgileSonderdruck

© Software & Support Media GmbH

die Nutzung des Unterstrichs für das Matching von be-liebigen String-Parametern.

Data-driven Tests mit SpockGute Unit-Tests sollten alle möglichen Varianten an Eingabedaten inklusive der Randbedingungen prüfen. In der Praxis führt dies leider häufig zu vielen kleinen Testmethoden. Oft werden diese schlicht kopiert und lediglich die Daten angepasst – der Wartbarkeitssuper-gau! In JUnit gibt es die @Parameterized-Annotation für solche Zwecke. Die Verwendung dieser Annotation ist aber alles andere als ausdrucksstark und intuitiv.

In Spock steht mit den Data Tables ein ausdrucks-starker Ansatz zur tabellarischen Spezifikation der Ein-gabe- und Ausgabedaten bereit. Die Definition erfolgt dabei im where-Block. Die Testmethode wird dann von Spock für jede Zeile der Datentabelle wiederholt aufge-rufen. Listing 4 zeigt einen solchen Test. Die Namen der Spalten lassen sich innerhalb der Testmethode als Va-riablen referenzieren. Auch die Verwendung der Werte innerhalb des Testnamens ist möglich. Hierfür muss die Methode mit der @Unroll-Annotation versehen werden.

Data Tables sind lediglich syntaktischer Zucker für den generischeren und sehr vielseitig einsetzbaren An-satz in Spock, den Data Pipes (Listing 5). Als Data Pipe kann in Spock im Grunde alles verwendet werden, über das in Groovy iteriert werden kann. In einem unserer Kundenprojekte haben wir z. B. diesen Mechanismus dazu verwendet, die Dokumente aus einer Apache-Solr-Suchmaschine zu laden, um diese dann mit Spock auf

Listing 1: Dependencies hinzufügen// choose Spock with desired Groovy dependencytestCompile 'org.spockframework:spock-core:1.1-groovy-2.4-rc-1'

// optional dependencies for using Spock// allows mocking of classes (in addition to interfaces)testRuntime 'cglib:cglib-nodep:3.2.4'

// allows mocking of classes without default constructortestRuntime 'org.objenesis:objenesis:2.4'

Listing 2: Beispieltestclass EchoSpec extends spock.lang.Specification { def "Check that echo replies 3 times"() { given: 'a fresh echo' def echo = new Echo()

when: 'we invoke the echo with a message' def reply = echo.reply('hello')

then: 'the message is returned 3 times' reply == 'hello hello hello' }}

ihre Konsistenz hin zu überprüfen. Als Datenquellen sind natürlich auch einfache CSV-Dateien oder die Ergebnisse von SQL-Abfragen auf eine Testdatenbank denkbar.

REST-Client-Tests mit Spock und WireMockIn Zeiten von Microservices und verteilten Architekturen braucht es einen leichtgewichtigen Ansatz, um die REST-Client-Komponenten eines Systems zu testen, ohne dabei gleich alle benötigten Endpoints starten zu müssen. Auch diese Komponenten sollten zunächst in Isolation und unter Laborbedingungen getestet werden können. Eine schlanke Lösung hierfür ist die Integration und Kombi-nation von Spock mit dem Framework WireMock.

„Ein Web-Service-Testdouble für alle Fälle“, so lautet die Beschreibung in der WireMock-Onlinedokumenta-tion [2]. Das Framework unterstützt ganz generell das Stubbing und Mocking von HTTP-Aufrufen. So lassen sich die Aufrufe aufzeichnen und später wieder abspielen. Auch Fehlersituation können einfach simuliert werden und noch vieles mehr. Eine mögliche Deployment-Vari-ante von WireMock ist die Verwendung der WireMock-Rule-Klasse in einem JUnit-Test. Und nachdem Spock auf JUnit aufsetzt, werden Rules auch von Spock unterstützt.

Listing 3: Mockclass GreeterSpec extends Specification { def "Call Greeter using a Mock and check interactions"() { given: 'a mock and our test subject' def greeting = Mock(Greeting) def kirk = new Greeter(greeting)

when: 'kirk says hello to Spock' def reply = kirk.sayHello('Spock', 3)

then: 'the message method is invoked exactly 3 times' 3 * greeting.message(_ as String) >>> ['Hello', 'Mr.', 'Spock']

and: 'the returned reply was built correctly' reply == 'Hello Mr. Spock' }}

Listing 4: Data Tablesclass PythagorasSpec extends Specification { @Unroll def "#a Quadrat + #b Quadrat = #c Quadrat (with Data Tables)"() { expect: Math.pow(a, 2) + Math.pow(b, 2) == Math.pow(c, 2).round(0)

where: a | b || c 1 | 4 || Math.sqrt(17) 2 | 5 || Math.sqrt(29) 3 | 6 || Math.sqrt(45) }}

Page 4: Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein Testframework, das bereits seit 2008 entwickelt wird [1]. Es ist somit kein komplett neues

javamagazin 11 | 20164 www.JAXenter.de

AgileSonderdruck

© Software & Support Media GmbH

Listing 6 zeigt die Verwendung der WireMock Rule zusammen mit dem WireMock Groovy Binding [3] in ei-nem Spock-Test. Zunächst werden sowohl die Rule, das Groovy Binding als auch unser Testsubjekt auf HTTP-Port 18080 konfiguriert. Die Instanz vom Book Ser vice-Client wird zusätzlich mit der @Shared-Spock-Annotation versehen. Diese sorgt dafür, dass die Initialisierung nur einmal erfolgt. Alle Tests der Featureklasse teilen sich die-selbe Instanz. Bei zustandslosen Komponenten wie unse-rem REST-Client ist dies kein Problem.

Im Set-up-Block der Testmethode definieren wir an-schließend das gewünschte Verhalten des Mocks. Durch die Verwendung des Groovy Bindings ist der Code aus-drucksstark und so gut wie selbsterklärend. Über die re-quest Closure wird das Request Matching auf den Pfad und die HTTP-Methode festgelegt. Komplexe Prüfun-gen auf Request-Header oder den kompletten Payload sind ebenfalls möglich. Die response Closure definiert die Eigenschaften und den Inhalt der HTTP Response. Zur besseren Lesbarkeit wurde der Response Body in eine separate Datei ausgelagert. Für kurze Antworten kann man den Body aber auch inline definieren.

Oberflächentests mit Spock und GebKommen wir nun zur Königsdisziplin des Testens: au-tomatisierte UI-Tests. Leider haben Oberflächentests immer noch den Ruf, langsam, komplex und schwer wartbar zu sein. Etwas zu Unrecht, wie wir finden – den richtigen Ansatz und das richtige Tooling voraus-gesetzt. Speziell in Projekten mit vielen verschiedenen Oberflächen und verzweigten Navigationswegen bringt diese Sorte von Tests unserer Erfahrung nach einen gro-ßen Mehrwert. Regressionen im Navigationsverhalten

lassen sich automatisiert leicht ermitteln, der manuelle Testauf-wand für Bestandsfunktionen und Masken sinkt gegen Null. In unseren Projekten hat sich ein akzeptanztestgetriebener Ansatz als Best Practice für Oberflächen-tests etabliert. Bisher basierte

unser Ansatz auf einer Mischung aus Cucumber-JVM mit einem Page-Object-API-Eigenbau in Kombination mit dem Selenium WebDriver. Mit Spock und dem Geb Framework geht das nun deutlich einfacher.

Bei Geb  [4] handelt es sich um ein Framework zur Browserautomatisierung. Wie auch das Spock Frame-work wurde Geb ursprünglich von einem Entwickler bei Gradleware ins Leben gerufen. Im Kern setzt Geb auf den WebDriver. Es bietet aber zusätzlich eine ausdrucksstar-ke Groovy DSL, eine an jQuery angelehnte Möglichkeit zur Selektion von Inhalten und Elementen sowie eine na-tive Unterstützung des Page-Object-Patterns für stabile und wartbare UI-Tests. Für weitere Details verweisen wir auf eine frühere Ausgabe vom Java Magazin [5].

Das Geb Framework ist vielseitig einsetzbar. Und so bietet es auch Integrationen für Testframeworks wie Spock, JUnit und TestNG. Listing 7 zeigt einen einfa-chen Test zum Aufruf einer Webseite sowie die Page-Object-Implementierung der Seite. Die Integration beider Frameworks wird im Wesentlichen über die Basisklassen GebSpec oder GebReportingSpec erledigt. Letztere spei-chert für jede Interaktion die HTML Response der Seite und fertigt einen Screenshot an. Die Analyse von Test-fehlern wird so vereinfacht. Die im Listing verwendete @Stepwise-Annotation sorgt dafür, dass Spock die Test-methoden in der Reihenfolge ihrer Deklaration ausführt.

Lebendige Dokumentation einfach aufbauenTests dienen nicht nur der Prüfung der korrekten Funk-tionsweise unserer Softwarekomponenten, sondern auch ihrer Dokumentation. So lassen sich technische Dokumentationen, z. B. Schnittstellenspezifikationen, sehr gut mit Tests realisieren. Der Vorteil ist, dass die-se Dokumente nicht veralten, sie sind Bestandteil des Softwareprojekts und werden mit jeder Änderung der Software mit aktualisiert. Man spricht dann von leben-diger Dokumentation. Bekannte Vertreter sind ATDD-Frameworks wie RSpec, FitNesse oder Cucumber.

Das Spock Framework bringt auch hier einige ein-fache Features mit. Alle Testmethoden tragen einen verständlichen und gut lesbaren Namen. Sie sind idea-

Listing 5: Data Pipeswhere:a << [1, 2, 3]b << [4, 5, 6]c = Math.sqrt(a * a + b * b)

Listing 6: WireMock Rule mit WireMock Groovy Bindingclass BookServiceClientSpec extends Specification {

@Rule WireMockRule wireMockRule = new WireMockRule(18080) def wireMock = new WireMockGroovy(18080)

@Shared @Subject def client = new BookServiceClient("http:// localhost:18080")

def "Find all books from a WireMock stub server using a JSON body file"() {

given: "a stubbed GET request for all books" wireMock.stub { request { method "GET" url "/book" } response { status 200 bodyFileName "books.json" headers { "Content-Type" "application/json" } } }

when: "we invoke the client to find all books" def books = client.findAll()

then: "we expect the correct number of books" books.size() == 2

and: "the mock to be invoked exactly once" wireMock.count { method "GET" url "/book" } == 1 }}

Page 5: Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein Testframework, das bereits seit 2008 entwickelt wird [1]. Es ist somit kein komplett neues

javamagazin 11 | 2016 5www.JAXenter.de

AgileSonderdruck

© Software & Support Media GmbH

lerweise als vollständiger Satz formuliert. Die einzelnen Blöcke der Tests sollten zusätzlich mit beschreibenden Labels versehen werden, sodass sich die Labels der given-when-then-Blöcke als ein zusammenhängender Satz lesen lassen. Zusätzlich bringt Spock etliche eigene Annotationen mit, um Testspezifikationen mit weiteren Informationen anzureichern. Über die @Subject-Anno-tation lässt sich die zu testende Klasse festlegen. Die An-notation wird auf Klassen- oder einfach auf Feldebene angewendet. Mit den @ Title- und @Narrative-Anno-tationen können zusätzliche Freitextinformationen auf Ebene der Spezifikationsklasse abgelegt werden, wie der Name und die Beschreibung einer entsprechenden User Story. Die @Is sue-Annotation erlaubt zudem den Ver-weis in ein externes Issue-Tracking-System, auf das sich ein Feature bezieht.

Spock bringt außer diesen Annotationen selbst keiner-lei Reportingfunktionen mit. Hier ist man auf externe Werkzeuge und Bibliotheken angewiesen, wie etwa die Spock Reporting Extension [6]. Diese generiert für jedes Feature einen einfachen HTML-Report und verwendet dabei die Informationen aus den Labels und Annotatio-nen (Abb. 2). Das Einbinden dieser Extension ist denk-bar einfach, es muss lediglich eine weitere Dependency hinzugefügt werden.

FazitAbschließend wollen wir noch der Frage nachgehen, wann und für welche Testarten das Spock Framework in einem Projekt eingesetzt werden sollte. Für Green-Field-Projekte ist unsere Empfehlung klar: von Beginn an, für alle Tests. Bei Bestandsprojekten ist die Situation na-türlich eine andere, denn es gibt hoffentlich bereits eine hohe Anzahl an Tests, die meist mit JUnit oder TestNG realisiert wurden. Klar ist, dass der komplette Wechsel des Testframeworks und die damit verbundenen Auf-

wände gegenüber dem Product Owner wohl nur schwer vermittelbar sein dürften. Stattdessen schlagen wir vor, Spock in solchen Fällen lediglich in ausgewählten Be-reichen zu verwenden, wie etwa für Integrations- oder Oberflächentests. Dieses Vorgehen hat sich in unseren Projekten als sinnvoll und praktikabel erwiesen.

Das Spock Framework ist unserer Meinung nach eine stabile und absolut zu empfehlende Alternative zu den etablierten Frameworks. Schon nach kurzer Zeit hat man sich an die Syntax von Spock gewöhnt. Das Schreiben von Tests geht durch die reduzierte Syntax zügig von der Hand und es macht unglaublichen Spaß. Die Stärken von Spock kommen speziell in den Berei-chen Data-driven Testing und Interaction-based Testing zum Tragen. Die gute Unterstützung von Spock in allen gängigen IDEs und Build-Tools ermutigt zusätzlich zum Einsatz von Spock auch in großen Enterprise-Projekten.

Die finale Entscheidung, ob Sie das Spock Framework in einem Ihrer nächsten Enterprise-Projekte mit auf eine Außenmission nehmen, liegt natürlich bei Ihnen: Test long and prosper!

Mario-Leander Reimer ist Cheftechnologe bei der QAware. Er ist Spezialist für den Entwurf und die Umsetzung von komplexen Sys-tem- und Softwarearchitekturen auf Basis von Open-Source-Tech-nologien. Als Mitglied im Java Community Process (JCP) ist sein Ziel, die Java-Plattform weiter zu verbessern und praxistaugliche Spezifikationen zu entwickeln.

Listing 7: Test zum Aufruf einer Webseite@Stepwiseclass HomePageSpec extends GebReportingSpec { def "Launch browser and navigate to index page"() { when: 'we navigate to the QAware homepage' go("http://www.qaware.de")

then: 'the index page is displayed with the correct headline' waitFor { at IndexPage } assertThat headline.text(), containsString("Qualität und Agilität") }}

class IndexPage extends Page { static url = "http://www.qaware.de" static at = { browser.title.contains("QAware") } static content = { headline { $("h1", 0) } }}

Abb. 2: Beispielausgabe der Spock Reports Extension

Links & Literatur

[1] Spock Framework Documentation: http://docs.spockframework.org

[2] WireMock Documentation: http://wiremock.org/docs/

[3] WireMock Groovy Binding: https://github.com/tomjankes/wiremock-groovy/

[4] The Book of Geb: http://www.gebish.org/manual/current/

[5] Kraft, Tobias: „Mr. Spock ruft Geb“, in: Java Magazin 1.2015

[6] Spock Reports Extension, GitHub: https://github.com/renatoathaydes/spock-reports/

Page 6: Java | Architektur | Software-Innovation AUTOMATISIERTES · Bei Spock handelt es sich um ein Testframework, das bereits seit 2008 entwickelt wird [1]. Es ist somit kein komplett neues

6

QAware GmbH München

Aschauer Straße 32

81549 München

Tel.: +49 (0) 89 23 23 15 – 0

Fax: +49 (0) 89 23 23 15 – 129

Mail: [email protected]

QAware GmbH Mainz

Rheinstraße 4 D

55116 Mainz

Tel.: +49 (0) 6131 215 69 – 0

Fax: +49 (0) 6131 215 69 – 68

Mail: [email protected]

IT-Probleme lösen. Digitale Zukunft gestalten.


Recommended