b+m Informatik AG
www.bmiag.de
Technologische Expertise im Software Engineering
Wartbare Oberflächentests mit Open-Source-Software
Nils Christian Ehmke
Oliver Libutzki
www.bmiag.de
• Der Weg zum wartbaren Test
• Erweiterte Konzepte
• Demo
Agenda
www.bmiag.de
Wartbare Oberflächentests mit Open-Source-Software
Der Weg zum wartbaren Test
www.bmiag.de 4
• Formulierung und Ausführung von integrativen UI-Tests
• Fokus auf Webanwendungen
• Fokus auf Lesbarkeit, Nachvollziehbarkeit und Wartbarkeit
• Formulierung in Java
• Don‘t reinvent the wheel
• Einsatz von Open-Source-Software
• Integration über definierte Schnittstellen
Prinzipien
Test API for Regressiontests
www.bmiag.de 5
Eingesetzte Frameworks/Tools
Browser-Automation
Entwicklungsumgebung
www.bmiag.de 6
Selenium Web Driver
• API zur Interaktion mit dem Browser
• Implementierungen in Java, C#, Ruby, Python und Javascript
• Implementierungen für alle gängigen Browser und headless
Selenium IDE
• Add-on für Firefox
• Capture-Replay-Funktionalität
• Export in Web Driver Format
Selenium
www.bmiag.de 7
Aktion Selenium-Befehl
„Cheese!“
in Suchfeld
eingeben
driver.findElement(By.id("lst-ib")).clear();
driver.findElement(By.id("lst-ib")).sendKeys("Cheese!");
„Lupe“
anklicken
driver.findElement(By.name("btnG")).click();
„Bilder“
anklicken
driver.findElement(By.cssSelector("a.q.qs")).click();
„Shopping“
anklicken
driver.findElement(
By.xpath("//a[contains(text(),'Shopping')]")).click();
„Web“
anklicken
driver.findElement(By.linkText("Web")).click();
Warum Tapir? Es gibt die Selenium IDE!
www.bmiag.de 8
Tests schreiben ist Programmieren!
In automated testing the Test Engineer
[…] must have software coding ability,
since the test cases are written in the
form of source code … (Test
automation, Wikipedia)
Many test automation tools provide record
and playback features […] reliance on
these features poses major reliability and
maintainability problems (Test automation,
Wikipedia)
www.bmiag.de 9
Google als Beispiel
WebDriver driver = new HtmlUnitDriver();
driver.get("http://www.google.com");
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();
System.out.println("Page title is: " +
driver.getTitle());
driver.quit();
Quelle: https://code.google.com/p/selenium/wiki/GettingStarted
www.bmiag.de 10
Eingesetzte Frameworks/Tools
Browser-Automation
Entwicklungsumgebung
Testfall-Ausführung
www.bmiag.de 11
JUnit-Integration
@Test
public void testGoogleSearch() {
WebDriver driver = new HtmlUnitDriver();
driver.get("http://www.google.com");
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();
assertThat(driver.getTitle(), is("Cheese! - Google
Search"));
driver.quit();
}
Integration über speziellen Runner
@RunWith(TapirBootstrapper.class)
www.bmiag.de 12
Browserunabhängigkeit
@Test
public void testGoogleSearch() {
WebDriver driver = new HtmlUnitDriver();
driver.get("http://www.google.com");
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();
assertThat(driver.getTitle(), is("Cheese! - Google
Search"));
driver.quit();
}
www.bmiag.de 13
Browserunabhängigkeit
@Test
public void testGoogleSearch() {
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com");
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();
assertThat(driver.getTitle(), is("Cheese! - Google
Search"));
driver.quit();
}
www.bmiag.de 14
Eingesetzte Frameworks/Tools
Browser-Automation
Entwicklungsumgebung
Testfall-Ausführung
Depedency-Injection /
Aspect oriented programming
www.bmiag.de 15
Browserunabhängigkeit
@Autowired
private WebDriver driver;
@Test
public void testGoogleSearch() {
driver.get("http://www.google.com");
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();
assertThat(driver.getTitle(), is("Cheese! - Google
Search"));
}
www.bmiag.de 16
@Test
public void testGoogleSearch() {
driver.get("http://www.google.com");
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();
assertThat(driver.getTitle(), is("Cheese! - Google
Search"));
}
Lesbarkeit / Nachvollziehbarkeit / Wartbarkeit
www.bmiag.de 17
HTML-Abhängigkeiten beseitigen
If you have WebDriver APIs in your test methods,
You're Doing It Wrong.
-- Simon Stewart (Creator of Selenium Web Driver)
Test
Page Object
Page
Component
Element
Interface
HTML
Test
Page Object
Page
Component
Element
Interface
HTML
www.bmiag.de 18
• Interfaces spiegeln die Möglichkeiten des Benutzers wider
• Beispiel CheckboxField:
• void click(), boolean isEnabled(), boolean isDisplayed(),
boolean isSelected()
Element-Interfaces
«interface» CheckboxField
DefaultSeleniumCheckboxField
MyAppCheckboxField
Tapir Core
Tapir Selenium
MyApp Test
www.bmiag.de 19
@Page
public class GoogleSearchPage {
@FindBy(name = "q")
private WebElement queryField;
@FindBy(name = "btnK")
private WebElement googleSearchButton;
@Autowired
private BeanFactory beanFactory;
public TextField getQueryField() {
…
}
public Button getGoogleSearchButton() {
…
}
}
Page-Objekte und Element-Interfaces
www.bmiag.de 20
@Autowired
private WebDriver driver;
@Autowired
private GoogleSearchPage googleSearchPage;
@Test
public void testGoogleSearch() {
driver.get("http://www.google.com");
googleSearchPage.getQueryField().setText("Cheese!");
googleSearchPage.getGoogleSearchButton().click();
assertThat(driver.getTitle(), is("Cheese! - Google
Search"));
}
Page-Objekte und Element-Interfaces
www.bmiag.de 21
Auslagerung zur Wiederverwendung
public class BrowserInteraction {
@Autowired
private WebDriver driver;
public void openURL(String url) {
driver.get(url);
}
public String getTitle() {
return driver.getTitle();
}
}
www.bmiag.de 22
Auslagerung zur Wiederverwendung
@Autowired
private BrowserInteraction browserInteraction;
@Autowired
private GoogleSearchPage googleSearchPage;
@Test
public void testGoogleSearch() {
browserInteraction.openURL("http://www.google.com");
googleSearchPage.getQueryField().setText("Cheese!");
googleSearchPage.getGoogleSearchButton().click();
assertThat(browserInteraction.getTitle(), is("Cheese!
- Google Search"));
}
www.bmiag.de 23
@Page
public class GoogleSearchPage {
@FindBy(name = "q")
private WebElement queryField;
@FindBy(name = "btnK")
private WebElement googleSearchButton;
@Autowired
private BeanFactory beanFactory;
public TextField getQueryField() {
…
}
public Button getGoogleSearchButton() {
…
}
}
Alles gut, wenn das Page-Objekt nicht wäre…
www.bmiag.de 24
Eingesetzte Frameworks/Tools
Browser-Automation
Entwicklungsumgebung
Testfall-Ausführung
Depedency-Injection /
Aspect oriented programming
Syntactic Sugar /
Code-Generierung
www.bmiag.de 25
Xtend
Xtend-
Compiler
Java-
Compiler
Bytecode
Active
Annotations
www.bmiag.de 26
Page-Objekte mit Xtend
@Page
class GoogleSearchPage {
@SeleniumElement(name="q")
TextField queryField
@SeleniumElement(name="btnK")
Button googleSearchButton
}
www.bmiag.de 27
@Autowired
extension BrowserInteraction
@Autowired
GoogleSearchPage googleSearchPage
@Test
def void testGoogleSearch() {
openURL("http://www.google.com")
googleSearchPage.queryField.text = "Cheese!"
googleSearchPage.googleSearchButton.click
assertThat(title, is("Cheese! - Google Search"));
}
Test mit Xtend
www.bmiag.de 28
Wir haben es geschafft!
@Test
def void testGoogleSearch() {
openURL("http://www.google.com")
googleSearchPage.queryField.text = "Cheese!"
googleSearchPage.googleSearchButton.click
assertThat(title, is("Cheese! - Google Search"));
}
@Test
public void testGoogleSearch() {
driver.get("http://www.google.com");
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();
assertThat(driver.getTitle(), is("Cheese! - Google
Search"));
}
www.bmiag.de
Wartbare Oberflächentests mit Open-Source-Software
Erweiterte Konzepte
www.bmiag.de 30
• Parallele Testausführung
• Feature-Modell zum Testen von Produktlinien
• schrittweise Testdefinition
• Testdatenanbindung
Erweiterte Konzepte
www.bmiag.de 31
Steps
@Autowired
extension BrowserInteraction
@Autowired
GoogleSearchPage googleSearchPage
@Step
def void openGoogleWebsite() {
openURL("http://www.google.com")
}
@Step
def void queryGoogle() {
googleSearchPage.queryField.text = "Cheese!"
googleSearchPage.googleSearchButton.click
assertThat(title, is("Cheese! - Google Search"));
}
www.bmiag.de 32
Data Provider
def static queryData() {
#["Cheese!", "Cake"]
}
@Step
def void openGoogleWebsite() {
openURL("http://www.google.com")
}
@Step
@DataProvidedBy("queryData")
def void testGoogleSearch(String queryData) {
googleSearchPage.queryField.text = queryData
googleSearchPage.googleSearchButton.click
assertThat(title, is(queryData + " - Google Search"));
}
www.bmiag.de 33
Eingesetzte Frameworks/Tools
Browser-Automation
Entwicklungsumgebung
Testfall-Ausführung
Depedency-Injection /
Aspect oriented programming
Syntactic Sugar /
Code-Generierung
Testergebnis-Reporting
Allure
www.bmiag.de 34
Visuelle Aufbereitung der Testergebnisse
www.bmiag.de 35
Eingesetzte Frameworks/Tools
Browser-Automation
Entwicklungsumgebung
Testfall-Ausführung
Depedency-Injection /
Aspect oriented programming
Syntactic Sugar /
Code-Generierung
Testergebnis-Reporting
Bau / Testausführung
außerhalb der IDE
Kontinuierliche Ausführung
Allure
www.bmiag.de 36
Kontinuierliche Ausführung
www.bmiag.de
Wartbare Oberflächentests mit Open-Source-Software
Demo
Kontakt
www.bmiag.de 39
Oliver Libutzki
Softwarearchitekt
b+m Informatik AG
Rotenhofer Weg 20
24109 Melsdorf
[oliver.libutzki@bmiag.de]
T +49 4340 404-1668
F +49 4340 404-111
Nils Christian Ehmke
Softwareentwickler
b+m Informatik AG
Rotenhofer Weg 20
24109 Melsdorf
[nils-christian.ehmke@bmiag.de]
T +49 4340 404-1686
F +49 4340 404-111

Wartbare Oberflächentests mit Open-Source-Software

Hinweis der Redaktion

  • #2 Vorstellung Nils und Oliver Vorstellung b+m Engineering: hilft bei Beratung, Planung und Umsetzung von IT-Vorhaben Fokus auf Banken- und Versicherungslösungen Warum ein neues Oberflächentest-Tool? Altes Tool seit 6 Jahren nicht weiterentwickelt Viele Testfälle nicht abbildbar Keine Akzeptanz bei Entwicklern
  • #3 Weg zu wartbarem Test aufzeigen
  • #5 Erwähnen Tapir selbst nicht Open-Source Fokus auf Methodik
  • #6 Eclipse / Selenium
  • #7 Vorteil headless kurz erläutern
  • #8 Aufgezeichnet mit Selenium IDE Dopplung bei der Suchfeld-Adressierung Jeweils anderer Zugriffspfad auf optisch ähnliche Elemente
  • #10 Einführen in das Beispiel Quelle: Getting started von der Web Driver Website
  • #11 Einführung JUnit
  • #12 Integration über Junit Runner Einbettung in Junit-Test-Methode Nutzung von Hamcrest
  • #13 Spezifischer Web-Driver wird instanziiert
  • #15 Einführung Spring
  • #16 Auf Spring eingehen: Möglichkeit die konkrete Implementierung von außen festzulegen Code ist unabhängig vom konkreten Browser (WebDriver)
  • #17 Test schwer lesbar und nachvollziehbar: Es ist nicht ersichtlich, dass das Suchfeld den Namen „q“ hat Dass die Suche über ein submit gestartet werden kann, ist ein Implementierungsdetail der getesteten Anwendung. Für den Benutzer nicht relevant. Benutzer würde Enter drücken oder aber auf „Google Search“ klicken. Wartbarkeit: Problematisch, wenn Google den Namen des Suchfeldes ändert.
  • #19  Darauf eingehen, dass Tapir nur das Interface und eine Default-Implementierung zur Verfügung stellt. Bzgl. MyApp auf die spezielle Implementierung der readonly-Checkboxen in Referenzanwendung eingehen
  • #20 Eingehen auf: Adressierung der HTML-Elemente (FindBy aus Selenium WebDriver) public-Methoden liefern Element-Interfaces
  • #26 Vorteile Xtend: statische Typisierung Java Typsystem Kompiliert zu Java IDE Support
  • #27 Nur auf die notwendigen Informationen beschränkt
  • #32 Eingehen auf die Möglichkeit die Methoden sequentiell auszuführen dank Xtend Active Annotations