Groovy kind of test

49
Groovy kind of Test

Transcript of Groovy kind of test

Groovy kind of Test

Torsten Mandry

© 2014 OPITZ CONSULTING Deutschland GmbH

MotivationSpock & Geb im Rahmen der Grails Lerngruppe GM

Einfache und Ausdrucksstarke Tests

Kann ich Spock & Geb auch in einem klassischen Java-Projekt einsetzen?

Was euch erwartetWas ist Groovy?

Was ist Spock?

Was ist Geb?

Wie kann ich Spock/Geb in einem klassischen Java Projekt einsetzen?

Was ihr nicht erwarten dürftUmfangreiche Einführung in Groovy

Erfahrungsbericht aus einem "echten" Projekt

abgeschlossenes Forschungsthema

WarnungDiese Präsentation kann spuren von Quellcode enthalten!

1 Groovy

Was ist Groovy?JVM Programmier- und Skript-Sprache

entwickelt in 2003 von James Strachan

2004 als JSR 241 in den Java Community Process aufgenommen(geleitet von Guillaume Laforge)

Open Source, Apache Software License 2

Aktuelle Version: 2.3.6

Homepage: http://groovy.codehaus.org/

Groovy Design-ZielDas Design-Ziel des ursprünglichen Entwicklers James Strachan bestand darin,

eine „geschliffene“ Fassung der Java-Syntax mit den Konzepten von Ruby zuverbinden.

Quelle: Wikipedia

Wichtigste Featureserweitert Java (d.h. gültiger Java Code ist gültiger Groovy Code*) )

optimiert Java (reduziert unnötigen Code, sinnvolle Defaults)

kompiliert zu Java Byte Code, läuft in einer JVM, integriert sich problemlos mit anderen Java Komponenten

optionale Typisierung

Native Unterstützung von Closures, Maps, Listen, regulären Ausdrücken,BigDecimals, BigIntegers, Unit Testing, Mocking, ...

Erweiterte Unterstützung von DB Access und XML/JSON Processing

...*) gilt nicht generell, aber in den meisten Fällen

Beispiel: Array- bzw. List-HandlingIn Java

for (String it : new String [] { "Rod", "Carlos", "Chris" }) System.out.println(it);

In Groovy

["Rod", "Carlos", "Chris"].each { println it }

Beispiel: Test class TrivialerTest {

@Test def "testet ein paar triviale Dinge"() { assert 1 + 1 == 2 assert 2 != 1 } }

2 Spock

Was ist Spock?Testing und Specification Framework für Java und Groovy

Intuitive und ausdrucksstarke DSL

Inspiriert von verschiedenen Sprachen und Frameworks (JUnit, RSpec, jMock, Mockito, Groovy, Scala, ...)

Homepage: https://code.google.com/p/spock/

SpecificationTest-Klasse, abgeleitet von spock.lang.Specification.

Besteht ausFields (z.B. für das System under Specification)

Fixture Methods (setup, cleanup, setupSpec und cleanupSpec)

Feature Methods (testen bzw. beschreiben die Features)

Helper Methods

PhasenSetup Fixture

Stimulus

Verify Response

Cleanup

BlocksDefinieren die Phasen

Verwendung von Java

Verfügbare Blöckesetup oder given

when/then oder expect

cleanup

where

Labeled Statements

Beispiel: given when then class MathSpec extends spock.lang.Specification {

def "Maximum von zwei nummerischen Werten"() { given: def a = 1 def b = 5 def c = 5

when: def r = Math.max(a, b)

then: r == c } }

Beispiel: expect class MathSpec extends spock.lang.Specification {

def "Maximum von zwei nummerischen Werten"() { expect: Math.max(1, 5) == 5 Math.max(2, 3) == 3 } }

Beispiel: exception class MathSpec extends spock.lang.Specification {

def "Division durch 0 löst ArithmeticException aus"() { when: 1.0 / 0

then: ArithmeticException e = thrown() e.message =~ "Division" } }

Beispiel: data-driven class MathSpec extends spock.lang.Specification {

def "Maximum von zwei nummerischen Werten"() { expect: Math.max(value1, value2) == result

where: value1 << [1, 2, 3] value2 << [5, 3, 7] result << [5, 3, 7] } }

Beispiel: data-table class MathSpec extends spock.lang.Specification {

@Unroll("Maximum von #value1 und #value2 ist #result") def "Maximum von zwei nummerischen Werten"() { expect: Math.max(value1, value2) == result

where: value1 | value2 | result 1 | 5 | 5 2 | 3 | 3 7 | 3 | 7 } }

3 Geb

Was ist Geb?Automatisierungswerkzeug für Web-Oberflächen(Very Groovy Browser automation)

Fokus auf einfache/intuitive Entwicklung

Homepage: http://www.gebish.org/

Best of breedGeb vereint...

die Stärke/Mächtigkeit von WebDriver

die Eleganz/Einfachheit von JQuery Content Selection

die Robustheit des Page Object Modellings

die Ausdrucksstärke von Groovy

Empfohlen: Verwendung mit Spock

Beispiel: Web 2.0 Taschenrechnerhttp://web2.0rechner.de/

Beispiel - Scripting Ansatz def "Addition von zwei Zahlen"() { given: go "http://web2.0rechner.de/"

expect: title == "Web 2.0 Taschenrechner"

when: $("a#num_1").click() $("a#A42").click() $("a#num_2").click() $("a#btn_equal").click()

then: $("input#input").value() == "3" }

Page-Object kapselt Seiten-Details class TaschenrechnerPage extends Page {

static url = "http://web2.0rechner.de/"

static at = { title == "Web 2.0 Taschenrechner" }

static content = { btn_1 { $("a#num_1") } btn_2 { $("a#num_2") } btn_add { $("a#A42") } btn_equals { $("a#btn_equal") } display { $("input#input") } } }

http://www.gebish.org/manual/current/pages.html#pages

Beispiel - Page-Object Ansatz def "Addition von zwei Zahlen"() { given: to TaschenrechnerPage

when: btn_1.click() btn_add.click() btn_2.click() btn_equals.click()

then: display.value() == "3" }

Page-Object kapselt Funktionalität class TaschenrechnerPage extends Page { ... static content = { btn { char c -> $("a#" + ids[c.toString()]) } result { display.value() } }

def ids = [ "1" : "num_1", ... "+" : "A42", "=" : "btn_equal" ]

def calculate( String formula ) { formula.chars.each { type it } type('=' as char) }

def type( char character ) { btn(character).click() } }

Beispiel - Funktionale Spezifikation def "Addition von zwei Zahlen"() { given: to TaschenrechnerPage

when: calculate("1+2")

then: result == "3" }

Beispiel - Spock Data-Table @Unroll("#formula ergibt #expectedResult") def "Addition von zwei Zahlen"() { given: to TaschenrechnerPage

when: calculate(formula)

then: result == expectedResult

where: formula | expectedResult "1+2" | "3" "2+3" | "6" "3+4" | "7" "4+5" | "9" "5+6" | "11" }

4 Verwendung in einemJava Projekt

Beispiel ProjektIC-Online (Postbank Systems)

Multi-Modul Maven Projekt

Java, Spring, JPA, JSF (Richfaces)

separates Maven Modul "groovy-functional-tests"

Schritt 1 - trivialer Groovy TestZiel: Maven Modul erweitern,

so dass der folgende Groovy Test ausgeführt wird class TrivialerTest {

@Test void "testet ein paar triviale Dinge"() { assert 1 + 1 == 2 assert 2 != 1 } }

Groovy & JUnit Dependency <dependencies> <dependency> <groupid>org.codehaus.groovy</groupid> <artifactid>groovy-all</artifactid> <version>2.2.1</version> </dependency>

<dependency> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>4.11</version> </dependency> </dependencies>

Groovy Source Paths <plugin> <groupid>org.codehaus.mojo</groupid> <artifactid>build-helper-maven-plugin</artifactid> <version>1.8</version> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals><goal>add-source</goal></goals> <configuration> <sources><source>src/main/groovy</sources> </configuration> </execution> <execution> <id>add-test-source</id> <phase>generate-test-sources</phase> <goals><goal>add-test-source</goal></goals> <configuration> <sources><source>src/test/groovy</sources> </configuration> </execution> </executions> </plugin>

Groovy Eclipse Compiler <plugin> <artifactid>maven-compiler-plugin</artifactid> <version>3.1</version>

<configuration> <compilerid>groovy-eclipse-compiler</compilerid> </configuration>

<dependencies> <dependency> <groupid>org.codehaus.groovy</groupid> <artifactid>groovy-eclipse-compiler</artifactid> <version>2.8.0-01</version> </dependency> <dependency> <groupid>org.codehaus.groovy</groupid> <artifactid>groovy-eclipse-batch</artifactid> <version>2.1.8-01</version> </dependency> </dependencies> </plugin>

http://docs.codehaus.org/display/GROOVY/Groovy-Eclipse+compiler+plugin+for+Maven

Test Classes vs. Test SourcesMaven sucht standardmäßig in den Test Sources nach *.java Test-Dateien

Groovy Dateien (mit Dateiendung *.groovy) werden daher nicht gefunden

=> Maven soll in den compilierten Klassen nach Tests suchen

<properties> <maven.test.search.classdir>true</maven.test.search.classdir> </properties>

mvn verify...[INFO] --- maven-surefire-plugin:2.10:test (default-test) @ groovy-functional-tests ---[INFO] Surefire report directory: D:\Projekte\Groovy_kind_of_Test\Sources\groovy-functional- tests\target\surefire-reports

-------------------------------------------------------T E S T S-------------------------------------------------------Running de.javandry.groovyfunctionaltests.TrivialTestTests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.314 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

...[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------

Schritt 2 - erste einfache Geb SpecZiel: Maven Modul erweitern, so dass

die folgende Geb Specification ausgeführt wird class LoginSpec extends GebReportingSpec { static final validCredentials = [username: 'pl2', password: '2lp']

def "login with valid credentials"() { given: to LoginPage

when: loginWith validCredentials

then: at IcUebersichtPage } }

LoginPage class LoginPage extends Page {

static url = "pages/login.xhtml"

static content = { username { $("#j_username") } password { $("#j_password") } loginButton { $("#loginButton") } }

void loginWith(def credentials) { username = credentials.username password = credentials.password loginButton.click() } }

GebConfig.groovy baseUrl = "http://localhost:8888/iconline/"

reportsDir = "target/surefire-reports/geb"

http://www.gebish.org/manual/current/configuration.html#configuration

Spock & Geb Dependencies <dependency> <groupid>org.spockframework</groupid> <artifactid>spock-core</artifactid> <version>0.7-groovy-2.0</version> <scope>test</scope> </dependency>

<dependency> <groupid>org.gebish</groupid> <artifactid>geb-spock</artifactid> <version>0.9.2</version> <scope>test</scope> </dependency>

<dependency> <groupid>org.seleniumhq.selenium</groupid> <artifactid>selenium-htmlunit-driver</artifactid> <version>2.26.0</version> <scope>test</scope> </dependency>

http://www.gebish.org/manual/current/intro.html#installation__usage

IC-Online Anwendung lokal startenIdee: Die funktionalen Tests testen die Anwendung so, wie der Anwender sie

auch verwenden würde, d.h. ausschließlich über die Oberfläche.

Verwendung des Maven Cargo Plugins

Starten eines lokalen Containers

Deployen der Anwendung

Ausführen von Specs mit Surefire <plugin> <groupid>org.apache.maven.plugins</groupid> <artifactid>maven-surefire-plugin</artifactid> <version>2.16</version>

<executions> <execution> <id>functional-tests</id> <phase>integration-test</phase> <goals> <goal>test</goal> </goals> <configuration> <includes> <include>**/*Spec.class</include> </includes> </configuration> </execution> </executions> </plugin>

http://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html

mvn verify...[INFO] --- maven-surefire-plugin:2.16:test (functional-tests) @ groovy-functional-tests ---[INFO] Surefire report directory: D:\Projekte\Groovy_kind_of_Test\Sources\ groovy-functional-tests\target\surefire-reports

-------------------------------------------------------T E S T S-------------------------------------------------------Running de.javandry.groovyfunctionaltests.LoginSpec

...

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.866 sec - \ in de.javandry.groovyfunctionaltests.LoginSpec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

...[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------

Das war's

Wie geht's weiter?Zustand herstellen

Verwendung Java Test-Data-Builder

Alternative Groovy Test-Data-Builder

Unit- und Integrationstests von Java-KlassenGroovy, Spock & Geb in Java Modul integrieren

Danke für eureAufmerksamkeit