Entwickler gut beraten: UI-Tests die Spaß machen · © CoreMedia | 2012-11-29 | 1 Entwickler gut...

Post on 24-Feb-2021

0 views 0 download

Transcript of Entwickler gut beraten: UI-Tests die Spaß machen · © CoreMedia | 2012-11-29 | 1 Entwickler gut...

www.coremedia.com © CoreMedia | 2012-11-29 | 1

Entwickler gut beraten: UI-Tests die Spaß machen Mark Michaelis

Martti Jeenicke

Über Uns

© CoreMedia | 2012-11-29 | 3 www.coremedia.com

Wer sind wir?

Mark Michaelis QA Architect

Martti Jeenicke Agile Coach

© CoreMedia | 2012-11-29 | 4 www.coremedia.com

Was macht CoreMedia?

Enterprise Web Content Management

Produkt-Haus

Headquarter in Hamburg

Produkt-entwicklung

© CoreMedia | 2012-11-29 | 6 www.coremedia.com

Produktentwicklung

Traditionell Engineering lastig

Agile Entwicklung (hauptsächlich Scrum)

Komponenten-Teams (Scrum im Großen)

Interaction und Frontend Design zunehmend wichtig

Besonders für Backend-UIs

Frontend

© CoreMedia | 2012-11-29 | 8 www.coremedia.com

Frontend Beispiel: CoreMedia Studio

© CoreMedia | 2012-11-29 | 9 www.coremedia.com

Frontend Beispiel: CoreMedia Studio

Redaktionstool als Rich Web Application

Ersatz für Desktop Anwendungen

Komponenten-Ansatz

Plug-in-basiert

Ajax (XHR)

Viele Technologien

Hohe Komplexität

© CoreMedia | 2012-11-29 | 10 www.coremedia.com

Anwendungsarchitektur

Studio Server (Web-App) Client (Browser)

Presentation

MVC

Remoting

Ajax Request

JSON

HTTP

Content REST Service

Ext JS

Ext Core ExtJS

Backend Server

Content Server Search …

Testen von UI-Komponenten

© CoreMedia | 2012-11-29 | 12 www.coremedia.com

Technischer Rahmen

Test-Setup durch viele Applikationsschichten:

Content-, Search-Server

Web-Application-Server

Browser/UI

Testen von Plug-ins im Redaktionstool (CoreMedia Studio)

Wir sind durch einige UI-Test-Frameworks gegangen

WinRunner, QF-Tests, Sahi, ….

heute: Selenium/WebDriver als Basis-Technologie

© CoreMedia | 2012-11-29 | 13 www.coremedia.com

Organisatorischer Rahmen

UI-Tests sind Teil der Defintion of Done von Teams

UI-Tests sind Teil unserer CI-Chain (Selenium Grid)

Scrum im Großen

Lernkurve ist bereits für UI steil

Koordination vieler Teams über eine Community of Practice

© CoreMedia | 2012-11-29 | 14 www.coremedia.com

Testen muß Spaß machen

Für Entwickler ist Testen häufig lästig

„Nur Doku schreiben ist schlimmer“

Ohne Spaß weniger Akzeptanz von DoD Richtlinien

Tests müssen einfach zu verstehen sein

Tests können sehr (zeit-)aufwändig sein (und müssen trotzdem Spaß machen)

Was hindert uns daran Spaß zu haben?

© CoreMedia | 2012-11-29 | 16 www.coremedia.com

Thread.sleep(1000);

Hm, Test ist noch rot

© CoreMedia | 2012-11-29 | 17 www.coremedia.com

Thread.sleep(1001);

… immer noch …

© CoreMedia | 2012-11-29 | 18 www.coremedia.com

Thread.sleep(2000);

… komisch …

© CoreMedia | 2012-11-29 | 19 www.coremedia.com

Unser UI-Test im Jenkins war rot

© CoreMedia | 2012-11-29 | 20 www.coremedia.com

Und was hast Du gemacht?

© CoreMedia | 2012-11-29 | 21 www.coremedia.com

Nach einem Neustart war er grün…

Oder auch…

© CoreMedia | 2012-11-29 | 23 www.coremedia.com

Der Test war rot. Ich habe 2 Tage versucht den Tests zu reparieren.

© CoreMedia | 2012-11-29 | 24 www.coremedia.com

Und, läuft er jetzt wieder?

© CoreMedia | 2012-11-29 | 25 www.coremedia.com

Es war doch die Funktionalität, die kaputt war

© CoreMedia | 2012-11-29 | 26 www.coremedia.com

Was macht keinen Spaß?

Flackernde Tests

„Thread.sleep()“

Broken Window

Tests statt Produkt fixen

UI-Änderungen machen alles in den Tests „Kaputt“

Schlechte Kosten-Nutzen-Relation von Tests

Schlechte Debug-Unterstützung

Unverständliche Tests (für Entwickler)

Organisatorischer Ansatz

© CoreMedia | 2012-11-29 | 28 www.coremedia.com

Entwickler mit ins Boot holen

Entwickler mit ins Boot holen

„Mach kaputt, was Dich kaputt macht!“

Verbindung von Code und Test-Framework ist wichtig

Teams bauen gemeinsam ein Test Framework

Als Basis für schnell geschriebenen Tests

Flexibel für UI-Änderungen

Enge Feedbackschleife mit den Entwicklern

z.B. Konzept von Webdrivers Expected Conditions ist bei Team-Vorstellung durchgefallen

Technischer Ansatz

© CoreMedia | 2012-11-29 | 30 www.coremedia.com

Primäre Design Prinzipien

Simplicity

Born to Fail

Succeed Fast

Reusable

Extensible

Nur Einfaches wird akzeptiert

Testen mit schlafwandlerischer Sicherheit

© CoreMedia | 2012-11-29 | 31 www.coremedia.com

Primäre Design Prinzipien

Simplicity

Born to Fail

Succeed Fast

Reusable

Extensible

Tests müssen scheitern können

gutes Reporting

wohldefiniertes Ende

© CoreMedia | 2012-11-29 | 32 www.coremedia.com

Primäre Design Prinzipien

Simplicity

Born to Fail

Succeed Fast

Reusable

Extensible

Im Erfolgsfall muss es schnell gehen

In IDE muss es schnell gehen

© CoreMedia | 2012-11-29 | 33 www.coremedia.com

Primäre Design Prinzipien

Simplicity

Born to Fail

Succeed Fast

Reusable

Extensible

Konzepte allgemein wiederverwendbar = Joala

Wiederverwendung über Team-Grenzen

© CoreMedia | 2012-11-29 | 34 www.coremedia.com

Primäre Design Prinzipien

Simplicity

Born to Fail

Succeed Fast

Reusable

Extensible

Test-Framework muss erweiterbar sein

Erweiterbar wie Produkt

© CoreMedia | 2012-11-29 | 35 www.coremedia.com

Design Prinzipien

Simplicity

Born to Fail

Succeed Fast

Reusable

Extensible

Namen

© CoreMedia | 2012-11-29 | 37 www.coremedia.com

Open Source by CoreMedia

Joala

powered by

Jangaroo

© CoreMedia | 2012-11-29 | 38 www.coremedia.com

Joalas Freunde

seit 4.11 vollständig

Evolution eines Tests

© CoreMedia | 2012-11-29 | 40 www.coremedia.com

Evolution eines Tests Aus Alt…

Was macht der nachfolgende Test… 15 sec.

© CoreMedia | 2012-11-29 | 41 www.coremedia.com

Evolution eines Tests Aus Alt…

@Test

void testDocUpdate() {

doc = cms.createDoc();

date1 = doc.getDate();

while (!searchServer.isIndexed(doc)) {

Thread.sleep(1000);

}

browser.open(„http://.../studio?id=“ + doc.getId());

Thread.sleep(2000);

browser.getElement(„text“).click();

browser.getElement(„text“).sendKeys(„lorem“);

browser.getElement(„save“).click();

Thread.sleep(500);

date2 = doc.getDate();

assertTrue(date2.after(date1));

}

© CoreMedia | 2012-11-29 | 42 www.coremedia.com

Evolution eines Tests Aus Alt…

WTF?

Test, vor 10 Jahren geschrieben, Entwickler inzwischen weg

Geht das besser?

© CoreMedia | 2012-11-29 | 43 www.coremedia.com

Evolution eines Tests … mach Neu!

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

Aha!

Beispiel-UI

© CoreMedia | 2012-11-29 | 45 www.coremedia.com

Beispiel-UI

© CoreMedia | 2012-11-29 | 46 www.coremedia.com

Beispiel-UI in ExtJS

Unter der Lupe

© CoreMedia | 2012-11-29 | 48 www.coremedia.com

Evolution eines Tests Test-Name

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

} Alle fehlgeschlagenen Tests

Testname Dauer Alter

>>> …StoryTest.scenario_document_change_updates_date 34.07 1

Jenkins Logo by C. Lowell & Frontside

© CoreMedia | 2012-11-29 | 49 www.coremedia.com

Evolution eines Tests Gherkin für mehr Lesbarkeit

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

Given document D exists

And document D is opened

When I change document D

Then modification date of document D is updated.

© CoreMedia | 2012-11-29 | 50 www.coremedia.com

Evolution eines Tests Referenzen

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

© CoreMedia | 2012-11-29 | 51 www.coremedia.com

Evolution eines Tests Conditions/Matcher

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

// required to open document

while (!searchServer.isIndexed(doc)) {

Thread.sleep(1000);

}

// … open document

© CoreMedia | 2012-11-29 | 52 www.coremedia.com

Evolution eines Tests Conditions/Matcher

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

searchServiceWrapper

.indexed(doc)

.assumeThat(equalTo(true)); // assumeTrue()

© CoreMedia | 2012-11-29 | 53 www.coremedia.com

Evolution eines Tests Conditions/Matcher

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

searchServiceWrapper

.indexed(doc)

.assumeThat(equalTo(true)); // assumeTrue()

© CoreMedia | 2012-11-29 | 54 www.coremedia.com

Evolution eines Tests UI-Wrapper als Ersatz für…

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

browser.getElement(„text“).click();

browser.getElement(„text“).sendKeys(„lorem“);

browser.getElement(„save“).click();

© CoreMedia | 2012-11-29 | 55 www.coremedia.com

Evolution eines Tests UI-Wrapper

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

@Inject DocumentPanel panel;

TextField field = panel.getTextField();

field.write(„lorem“);

panel.saveDocument();

© CoreMedia | 2012-11-29 | 56 www.coremedia.com

Evolution eines Tests UI-Wrapper einfach geschrieben

@Test

void scenario_document_change_updates_date() {

Reference<Document> doc = ref();

given_document_D_exists(doc);

given_document_D_is_opened(doc);

when_I_change_document_D(doc);

then_modification_date_of_document_D_is_updated(doc);

}

@Inject DocumentPanel panel;

TextField field = panel.getTextField();

field.write(„lorem“);

panel.saveDocument();

@ExtJSObject(id = „docPanel“)

DocumentPanel extends ExtPanel {

@FindByExtJS(itemId=„save“) Button saveButton;

saveDocument() {

saveButton.click();

}

© CoreMedia | 2012-11-29 | 57 www.coremedia.com

Evolution eines Tests Wrapper: Für Entwickler

Hierarchie in ExtJS Hierarchie in Wrappern

© CoreMedia | 2012-11-29 | 58 www.coremedia.com

GridView extends Base {

GridDragZone getDragZone();

Condition<WebElement> cellElement(row ,column);

Condition<WebElement> rowElement(row);

void dragRowFromTo(fromRow,toRow);

BooleanCondition empty();

}

Evolution eines Tests UI-Wrapper – Ein Beispiel aus dem Leben

Was Wrapper wrappen

© CoreMedia | 2012-11-29 | 60 www.coremedia.com

Evolution eines Tests UI-Wrapper verstecken Komplexität, JavaScript

self = Ext.getCmp(„panel“);

key = „itemId“; value = „save“;

btn = (self.find && self.find(key, value)[0])

|| (self.buttons

&& self.buttons.filter(

function(b){return b[key] && b[key]==value})[0])

|| (self.items

&& self.items.filter(key, value).get(0));

© CoreMedia | 2012-11-29 | 61 www.coremedia.com

Evolution eines Tests UI-Wrapper verstecken Komplexität, DOM-Struktur

<table cellspacing="0" class="x-toolbar-ct"><tbody>

<tr>

<td class="x-toolbar-left" align="left">

<table cellspacing="0"><tbody>

<tr class="x-toolbar-left-row"></tr>

</tbody></table>

</td>

<td class="x-toolbar-right" align="right">

<table cellspacing="0" class="x-toolbar-right-ct"><tbody>

<tr>

<td>

<table cellspacing="0"><tbody>

<tr class="x-toolbar-right-row">

<td class="x-toolbar-cell" id="ext-gen317">

<table id="ext-comp-1314" cellspacing="0" class="x-btn x-btn-noicon" style="width: 75px;">

<tbody class="x-btn-small x-btn-icon-small-left">

<tr>

<td class="x-btn-tl"><i>&nbsp;</i></td>

<td class="x-btn-tc"></td>

<td class="x-btn-tr"><i>&nbsp;</i></td>

</tr>

<tr>

<td class="x-btn-ml"><i>&nbsp;</i></td>

<td class="x-btn-mc">

<em class="" unselectable="on">

<button type="button" id="ext-gen318" style="" class=" x-btn-text">Bestätigen</button> </em>

Zusammen- fassung

© CoreMedia | 2012-11-29 | 63 www.coremedia.com

Zusammenfassung

UI-Test machen Spaß

näher am Produkt

SOLID

schneller schreiben

Fehler werden schnell gefunden

Grüne Radiator Views

Entwickler gut beraten

Ideen von Entwickler aufgesammelt und weiterverteilt

Wissensinseln abgebaut

Teams sprechen dieselbe Sprache

Teams helfen Teams (CoP)

Weiterentwicklung durch alle

© CoreMedia | 2012-11-29 | 64 www.coremedia.com

CONTENT | CONTEXT | CONVERSION

Mark Michaelis mark.michaelis@coremedia.com

Martti Jeenicke martti.jeenicke@coremedia.com

http://bit.ly/xdde12-uitestfun

Bonusmaterial

© CoreMedia | 2012-11-29 | 66 www.coremedia.com

Bonusmaterial

Bonusmaterial für eine nachfolgende Diskussion

im Download enthalten für weitere Informationen

Expected Conditions

© CoreMedia | 2012-11-29 | 68 www.coremedia.com

Verantwortlichkeiten WebDriver Wait Pattern

© CoreMedia | 2012-11-29 | 69 www.coremedia.com

Verantwortlichkeiten Joala Wait-Pattern

© CoreMedia | 2012-11-29 | 70 www.coremedia.com

Terminierung WebDriver Wait Pattern

© CoreMedia | 2012-11-29 | 71 www.coremedia.com

Terminierung Joala Wait Pattern

© CoreMedia | 2012-11-29 | 72 www.coremedia.com

Verwendung im Test WebDriver Wait Pattern

© CoreMedia | 2012-11-29 | 73 www.coremedia.com

Verwendung im Test Joala Wait Pattern

BDD-Logging

© CoreMedia | 2012-11-29 | 75 www.coremedia.com

BDD-Logging mit Spring-AOP

STORY: .......... Story 776 Open Collection View

SCENARIO: ....... show document

..... given a folder has been created

..... given a document has been created in the folder

..... when the document is shown in the collection view in thumbnail mode

..... then the collection view is in repository mode

..... then the collection view is in thumbnail mode

..... then the folder is the current folder

..... then the document is selected in the repository thumbnails view