View
0
Download
0
Category
Preview:
Citation preview
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> </i></td>
<td class="x-btn-tc"></td>
<td class="x-btn-tr"><i> </i></td>
</tr>
<tr>
<td class="x-btn-ml"><i> </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
Recommended