219
Prof. Dr. Stephan Kleuker 549 6.11 Testen von Web-Applikationen - Selenium Web-Browser nutzen schwerpunktmäßig HTML zur Darstellung Capture & Replay-Werkzeuge, die hardgecoded Pixel und Klicks verarbeiten, eignen sich meist auch für diese Programme Einfaches Werkzeug für Web-Applikationen und Firefox ist Selenium IDE [hier nicht gezeigt] (http://seleniumhq.org/ ) erlaubt Capture & Replay von Nutzereingaben ermöglicht Tests von Elementen, Identifizierung über Ids aber auch Beschriftungen erlaubt den Export der aufgezeichneten Tests u. a. in JUnit (Variante: Browsersteuerung aus JUnit heraus [nächste Folien], ähnlich FEST) basiert auf JavaScript und Iframes Komponentenbasierte Software- Entwicklung

6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

549

6.11 Testen von Web-Applikationen - Selenium

• Web-Browser nutzen schwerpunktmäßig HTML zur Darstellung

• Capture & Replay-Werkzeuge, die hardgecoded Pixel und Klicks verarbeiten, eignen sich meist auch für diese Programme

• Einfaches Werkzeug für Web-Applikationen und Firefox ist Selenium IDE [hier nicht gezeigt] (http://seleniumhq.org/)

– erlaubt Capture & Replay von Nutzereingaben

– ermöglicht Tests von Elementen, Identifizierung über Idsaber auch Beschriftungen

– erlaubt den Export der aufgezeichneten Tests u. a. in JUnit (Variante: Browsersteuerung aus JUnit heraus [nächste Folien], ähnlich FEST)

– basiert auf JavaScript und Iframes

Komponentenbasierte Software-Entwicklung

Page 2: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

550

Hinweise zum Testen

• Erinnerung: White Box – Grey Box – Black Box

• Basisfunktionalität mit JUnit testen

• einige Funktionalität ohne Server testbar

• gibt einfache Server nur zur Testausführung

• Selenium WebDriver ermöglicht Test der (Web-)Oberfläche

• niemals alle Tests durch Oberflächentests ersetzen

• es gibt nie das ultimative Werkzeug; aber Familie von Werkzeugen hilft oft

• nur automatisieren, wenn sinnvoll

• Ziel: Continuous Integration

Komponentenbasierte Software-Entwicklung

Page 3: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

551

Selenium WebDriver

• Selenium steuert Browser von Java (C#, Python, Ruby) aus

• Installation als jar-Dateien

• flexible Möglichkeiten zum Finden von GUI-Komponenten

• ideal für Regressionstests, bei wenig sich ändernden GUIs

• in fast allen Unternehmen genutzt, die Web-Applikationen herstellen

• kontinuierliche Weiterentwicklung (nicht immer alles übertragbar, Selenium -> Selenium 2)

• Grundregel: nur automatisieren, was sinnvoll und machbar ist, Rest manuell

• http://docs.seleniumhq.org/docs/

Komponentenbasierte Software-Entwicklung

Page 4: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

552

Selenium WebDriver - Konfiguration

• unterstützt alle gängigen Browser

• bei neuen Browsern muss eventuell auf Aktualisierung von WebDriver gewartet werden

• Oft kleine zusätzliche Programme pro Browser benötigt

– Firefox: geckodriver (https://github.com/mozilla/geckodriver/releases) Proxy für Marionette

• über Nutzer-Profile nachdenken

• generell Browser-Version nutzen, der vor der genutzten Selenium-Version fertig war

• generell notwendig: eigene Testumgebung

• typisch: Testserver mit fester Konfiguration; nicht notwendigerweise neuestem Browser

Komponentenbasierte Software-Entwicklung

Page 5: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

553

Beispielprogramm (1/3)

• Spezifikation: Zu entwickeln ist eine Applikation mit der geheime Nachrichten an einen Server übergeben und dort wieder abgefragt werden können. Genauer gibt der Nutzer eine Nachricht zusammen mit zwei Codewörtern und der Anzahl, wie oft die Nachricht abgerufen werden kann, ein. Weiterhin kann ein Nutzer über die Eingabe zweier Codewörter an gespeicherte Nachrichten kommen. Ist die Codewortkombination nicht vorhanden, wird ein Standardtext ausgegeben.

• Realisierung: Glassfish, JSF (Nutzung des Application Scope)

Komponentenbasierte Software-Entwicklung

Page 6: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

554

Beispielprogramm (2/3)

Server starten

Applikation starten

http://localhost:8080/SecretSafe/

Komponentenbasierte Software-Entwicklung

vergebene Ids:

main:verfassen

main:lesen

Page 7: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

555

Beispielprogramm (3/3)Nachricht verfassen Nachricht lesen

Komponentenbasierte Software-Entwicklung

eingabe:c1

eingabe:c2

eingabe:geheim

eingabe:ab

eingabe:verschicken

abfrage:c1

abfrage:c2

abfrage:abfragen

antwort:Nachricht

Page 8: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

556

Einblick in Nutzungsmöglichkeiten (1/14)public class SafeMoeglichkeitenTest {

private WebDriver driver;

private int linie = 0; // nur Ausgabespielerei

@BeforeClass

public static void setUpOnce() {

System.setProperty("webdriver.gecko.driver"

, "F:\\Programme\\geckodriver\\geckodriver.exe");

}

@Before

public void setUp() {

// DesiredCapabilities ieCapabilities =

// DesiredCapabilities.internetExplorer();

driver = new FirefoxDriver();

// driver = new HtmlUnitDriver();

// driver = new ChromeDriver();

// driver = new InternetExplorerDriver(ieCapabilities);

}

Komponentenbasierte Software-Entwicklung

Page 9: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

557

Einblick in Nutzungsmöglichkeiten (2/14)

• Klasse WebDriver als zentrale Steuerungsmöglichkeit

• Erzeugt neue Browser-Instanz

• Browser muss auf dem System installiert sein, nutzt keine weiteren Einstellungen des aktuellen Nutzers (leeres Profil)

• werden kontinuierlich weiterentwickelt

• (früher reichte driver = new InternetExplorerDriver(); )

• bisheriges Angebot (unterschiedliche Qualität): HtmlUnitDriver(), FirefoxDriver(), InternetExplorerDriver(), ChromeDriver(),

• OperaDriver durch andere Entwickler, IPhoneDriver nur zusammen mit Apple-XCode-Umgebung, AndroidDriver mit Android-Entwicklungsunterstützung

• Hintergrund: Selenium lange Zeit nur mit Firefox nutzbar

Komponentenbasierte Software-Entwicklung

Page 10: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

558

Einblick in Nutzungsmöglichkeiten (3/14)

• Zentrale Hilfsklasse für GUI-Komponenten: WebElement• nur zur Veranschaulichung: Ausgabemöglichkeit

private void zeigeElemente(List<WebElement> liste){

System.out.println("----"+(++linie));

if (liste != null) {

for (WebElement w : liste) {

System.out.println(" " + w.getTagName()

+ "::" + w.getAttribute("type")

+ "::" + w.getAttribute("name")

+ "::" + w.getAttribute("value")

+ "::" + w.getText()

+ "::" + w.getLocation() + "::" +w.isEnabled());

}

}

}

Komponentenbasierte Software-Entwicklung

Page 11: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

559

Einblick in Nutzungsmöglichkeiten (4/14)

• Überblick über generierte HTML-Seite

• In Entwicklung sinnvolle Ids/Namen vergeben

• JSF: Ids eindeutig

• Zugriff auch ohne Ids machbar („drittes Input-Element“)Komponentenbasierte Software-

Entwicklung

Page 12: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

560

Einblick in Nutzungsmöglichkeiten (5/14)

@Test

public void testBeispielvarianten()

throws InterruptedException, IOException {

// Seite aufrufen

driver.get("http://localhost:8080/SecretSafe/");

List<WebElement> liste =

driver.findElements(By.tagName("input"));

zeigeElemente(liste);

----1

input::hidden::main::main::::(0, 0)::true

input::submit::main:verfassen::Nachricht verfassen::::(8, 129)::true

input::submit::main:lesen::Nachricht lesen::::(8, 153)::true

input::hidden::javax.faces.ViewState::2158484851038199978:-

1608245938470041174::::(0, 0)::true

Komponentenbasierte Software-Entwicklung

Page 13: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

561

Einblick in Nutzungsmöglichkeiten (6/14)

List<WebElement> inp = driver.findElements(

By.xpath("//input"));

zeigeElemente(inp);

----2

input::hidden::main::main::::(0, 0)::true

input::submit::main:verfassen::Nachricht verfassen::::(8, 129)::true

input::submit::main:lesen::Nachricht lesen::::(8, 153)::true

input::hidden::javax.faces.ViewState::2158484851038199978:-

1608245938470041174::::(0, 0)::true

Komponentenbasierte Software-Entwicklung

Page 14: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

562

Einblick in Nutzungsmöglichkeiten (7/14)

• Viele weitere LokalisierungsmöglichkeitenMethod Summary

static By className(java.lang.String className)

static By cssSelector(java.lang.String selector)

WebElement findElement(SearchContext context)

List<WebElement> findElements(SearchContext context)

static By id(java.lang.String id)

static By linkText(java.lang.String linkText)

static By name(java.lang.String name)

static By partialLinkText(java.lang.String linkText)

static By tagName(java.lang.String name)

static By xpath(java.lang.String xpathExpression)

Komponentenbasierte Software-Entwicklung

Page 15: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

563

Einblick in Nutzungsmöglichkeiten (8/14)

• Steuerungsmöglichkeiten mit submit(), click(), weiteren Eingabemöglichkeiten

WebElement element =

driver.findElement(By.name("main:verfassen"));

System.out.println(element.getTagName()

+ "::" + element.getAttribute("type")

+ "::" + element.getAttribute("name")

+ "::" + element.getAttribute("value"));

element.click();

input::submit::main:verfassen::Nachricht verfassen

Komponentenbasierte Software-Entwicklung

Page 16: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

564

Einblick in Nutzungsmöglichkeiten (9/14)(new WebDriverWait(driver, 10)).until(

new ExpectedCondition<WebElement>() {

@Override

public WebElement apply(WebDriver d) {

return d.findElement(By.id("eingabe"));

}

});

System.out.println(driver.findElement(By.tagName("body")).getText());

Codewort 1:

Codewort 2:

geheime Nachricht:

wie oft abrufbar:

Zur Startseite

// Hilfsvariable für folgende Berechnung

List<WebElement> labels =

driver.findElements(By.tagName("input"));

Komponentenbasierte Software-Entwicklung

Warten bis Element erscheint

Page 17: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

565

Einblick in Nutzungsmöglichkeiten (10/14)

• es besteht die Möglichkeit JavaScript direkt auszuführen

• Mächtige Möglichkeiten, z. B. um Skripte zu starten oder Seite zu analysieren

• hier mit Übergabe und Rückgabe

@SuppressWarnings("unchecked")

List<WebElement> inputs2 = (List<WebElement>)

((JavascriptExecutor)driver).executeScript(

"var lbls = arguments[0]; "

+ "var inputs = []; "

+ "for (var i=0; i < lbls.length; i++){"

+ " inputs.push(document.getElementById("

+ " lbls[i].getAttribute('name'))); "

+ "} "

+ "return inputs;„ , labels);

zeigeElemente(inputs2);

Komponentenbasierte Software-Entwicklung

Aufrufparameter

Parameter für Aufruf

Page 18: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

566

Einblick in Nutzungsmöglichkeiten (11/14)

• Ausgabe zur letzten Folie

form::null::eingabe::null::Codewort 1:

Codewort 2:

geheime Nachricht:

wie oft abrufbar:

Zur Startseite::(8, 109)::true

input::text::eingabe:c1::::::(92, 109)::true

input::text::eingabe:c2::::::(92, 131)::true

input::text::eingabe:geheim::::::(138, 153)::true

input::text::eingabe:ab::0::::(120, 175)::true

input::submit::eingabe:verschicken::Verschicken::::(8,

197)::true

Komponentenbasierte Software-Entwicklung

Page 19: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

567

Einblick in Nutzungsmöglichkeiten (12/14)Object[] werte = {"input", "text"};

@SuppressWarnings("unchecked")

List<WebElement> inputs3 = (List<WebElement>)

((JavascriptExecutor) driver).executeScript(

"var tmp = document.getElementsByTagName(arguments[0]); "

+ "var erg = []; "

+ "for (var i=0; i<tmp.length; i++){"

+ " if(tmp[i].type==arguments[1]){"

+ " erg.push(tmp[i])"

+ " }"

+ "}; "

+ "return erg;", werte);

input::text::eingabe:c1::::::(92, 109)::true

input::text::eingabe:c2::::::(92, 131)::true

input::text::eingabe:geheim::::::(138, 153)::true

input::text::eingabe:ab::0::::(120, 175)::true

Komponentenbasierte Software-Entwicklung

Page 20: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

568

Einblick in Nutzungsmöglichkeiten (13/14)

// Gibt Seitentitel auf Konsole aus

System.out.println("Titel der Seite ist: "

+ driver.getTitle());

// Bildschirmfoto

File screenshot = ((TakesScreenshot)driver)

.getScreenshotAs(OutputType.FILE);

FileUtils.copyFile(screenshot,

new File("bild"+new Date().getTime()+".png"));

Assert.assertTrue(driver.getTitle().contains("Pssst"));

}

Komponentenbasierte Software-Entwicklung

Page 21: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

569

Einblick in Nutzungsmöglichkeiten (14/14)

• nach mehren Testläufen

Komponentenbasierte Software-Entwicklung

Page 22: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

570

Projektaufbau

• zentral benötigte Bibliotheken im Selenium-Download

Komponentenbasierte Software-Entwicklung

(alle) benötigt; evtl.

testng weglassen

benötigt (aktuelle

Variante)

Page 23: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

571

Weitere Funktionalität

• Wechsel zwischen Fenstern und zwischen Frames

• Möglichkeit vorwärts und zurück zu navigieren

• Nutzung von Cookies

• (Versuch der) Unterstützung von Drag und Drop

• Proxy-Nutzung

• Einstellung von Wartezeiten

• Warten auf das Erscheinen von HTML-Elementen (wichtig in Richtung AJAX und HTML5)

• Zusammenspiel mit Selenium IDE zur Testaufzeichnung

Komponentenbasierte Software-Entwicklung

Page 24: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

572

Achtung: Viele Einstiegsfallen

• generell gute Einarbeitungsmöglichkeit durch gute Dokumentation

• trotzdem viele kleine Fehlerquellen, die Entwicklungsprozess bremsen können

• Beispiel: Tests ziehen auf anderen Rechner um

• wichtiges Detail aus der Doku "The browser zoom level must be set to 100% so that the native mouse events can be set to the correct coordinates." (nicht erster Google-Treffer)

• teilweise weitere Browser-Einstellungen beachten

• Browser-Updates benötigen teilweise Selenium-Updates

• Fazit: Testrechner nie zu anderen Zwecken nutzen, Konfiguration sichern

Komponentenbasierte Software-Entwicklung

Page 25: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

573

Weitere Steuerungsvarianten

• Warten, bis Element vorhanden ist(new WebDriverWait(driver, 10)).until(

new ExpectedCondition<WebElement>(){

@Override

public WebElement apply(WebDriver d) {

return d.findElement( By.name("j_idt8:j_idt10"));

}});

• Steuerungsvariante mit JavaScriptWebElement but =

driver.findElement(By.name("j_idt8:j_idt10"));

((IJavaScriptExecutor)driver)

.executeScript("arguments[0].fireEvent('onclick');", but);

Komponentenbasierte Software-Entwicklung

Page 26: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

574

Test des Beispiels (1/7)

public class SecretSafeTest {

private WebDriver driver;

private static String text1;

private static String text2;

private File f = new File("C:\\Users\\x\\AppData\\"

+ "Roaming\\Mozilla\\Firefox\\Profiles\\zm12egmo.default");

private FirefoxProfile profile = new FirefoxProfile(f);

@BeforeClass

public static void setupClass() {

text1 = "" + Math.random(); // nicht ganz QS-sauber

text2 = "" + Math.random(); // zufaellige Texte

System.setProperty("webdriver.gecko.driver"

, "F:\\Programme\\geckodriver\\geckodriver.exe");

}

@Before

public void setUp() {

driver = new FirefoxDriver(profile);

}Komponentenbasierte Software-

Entwicklung

Page 27: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

575

Test des Beispiels (2/7)@After

public void tearDown() {

driver.quit(); // dauert, sonst nur am Ende aller Tests

}

// zur Erkennung, ob Seite bereits geladen ist

private void warteAufSeiteMitId(String id) {

(new WebDriverWait(driver, 10)).until(

new ExpectedCondition<WebElement>() {

@Override

public WebElement apply(WebDriver d) {

return d.findElement(By.id(id));

}

});

}

private void startSeite(){

driver.get("http://localhost:8080/SecretSafe");

}

Komponentenbasierte Software-Entwicklung

Page 28: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

576

Test des Beispiels (3/7)

private void eingabeSeite(){

startSeite();

warteAufSeiteMitId("main");

driver.findElement(By.name("main:verfassen")).click();

warteAufSeiteMitId("eingabe");

}

private void ausgabeSeite(){

startSeite();

warteAufSeiteMitId("main");

driver.findElement(By.name("main:lesen")).click();

warteAufSeiteMitId("abfrage");

}

private void feldFuellen(String name, String wert){

driver.findElement(By.name(name)).clear();

driver.findElement(By.name(name)).sendKeys(wert);

}

Komponentenbasierte Software-Entwicklung

Page 29: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

577

Test des Beispiels (4/7)private void textEingeben(String text1, String text2,

String geheim, int versuche){

eingabeSeite();

feldFuellen("eingabe:c1",text1);

feldFuellen("eingabe:c2",text2);

feldFuellen("eingabe:geheim",geheim);

feldFuellen("eingabe:ab",""+versuche);

driver.findElement(By.name("eingabe:verschicken")).click();

warteAufSeiteMitId("erfolg");

Assert.assertTrue(driver.findElement(By.tagName("body"))

.getText().contains("Eintrag erfolgreich"));

}

private void textEingeben(String geheim, int versuche){

textEingeben(this.text1, this.text2, geheim, versuche);

}

Komponentenbasierte Software-Entwicklung

Page 30: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

578

Test des Beispiels (5/7)

private void textErfolgreichSuchen(String text1,

String text2, String geheim){

ausgabeSeite();

feldFuellen("abfrage:c1",text1);

feldFuellen("abfrage:c2",text2);

driver.findElement(By.name("abfrage:abfragen")).click();

warteAufSeiteMitId("antwort");

Assert.assertTrue(driver.findElement(By.tagName("body"))

.getText().contains(geheim));

}

private void textErfolglosSuchen(String text1, String text2){

ausgabeSeite();

feldFuellen("abfrage:c1",text1);

feldFuellen("abfrage:c2",text2);

driver.findElement(By.name("abfrage:abfragen")).click();

warteAufSeiteMitId("antwort");

Assert.assertTrue(driver.findElement(By.tagName("body"))

.getText().contains("Treffen um 730 in KN2"));

}Komponentenbasierte Software-Entwicklung

Page 31: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

579

Test des Beispiels (6/7)private void textErfolgreichSuchen(String geheim){

textErfolgreichSuchen(text1, text2, geheim);

}

private void textErfolglosSuchen(){

textErfolglosSuchen(text1, text2);

}

@Test

public void testErfolglos(){

textErfolglosSuchen();

}

@Test

public void testEintragenUndLesen(){

textEingeben("TextText", 3);

textErfolgreichSuchen("TextText");

textErfolgreichSuchen("TextText");

textErfolgreichSuchen("TextText");

textErfolglosSuchen();

}Komponentenbasierte Software-

Entwicklung

Page 32: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

580

Test des Beispiels (7/7)

@Test

public void testLinkLesen(){

ausgabeSeite();

driver.findElement(By.linkText("Zur Startseite")).click();

warteAufSeiteMitId("main");

Assert.assertTrue(driver.findElement(By.tagName("body"))

.getText().contains("Was wollen Sie machen?"));

}

@Test

public void testLinkSchreiben(){

eingabeSeite();

driver.findElement(By.linkText("Zur Startseite")).click();

warteAufSeiteMitId("main");

Assert.assertTrue(driver.findElement(By.tagName("body"))

.getText().contains("Was wollen Sie machen?"));

}

// weitere Tests sinnvoll

}Komponentenbasierte Software-Entwicklung

Page 33: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

581

Testarchitektur

• Tests müssen für Änderbarkeit konzipiert werden

• häufig: viele Tests für eine konkrete Version geschrieben, nach leichten Änderungen der zu testenden Software werden Tests als unwartbar weggelegt

• Problem: ähnlich wie Software-Architektur wird Test-Architektur benötigt

• ein Ansatz: jeweils eigene Steuerungsklasse für eine Web-Seite, Tests arbeiten nur auf diesem Abstraktionslevel

• kleine Änderungen führen zu kleinen Änderungen in der Steuerungsklasse und keinen Änderungen bei deren Nutzern

• durch Abstraktion muss nicht jeder Tester Selenium können

• -> Tests müssen von qualifizierten Software-Entwicklern geschrieben werden

Komponentenbasierte Software-Entwicklung

Page 34: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

582Komponentenbasierte Software-Entwicklung

Design-Tests

• Browser stellen identische Inhalte leicht verändert da

• technisch überflüssig, aber wichtig für den Zeitgeist: modische Design-Anpassungen

• Für IT-Profi: Sisyphos-Arbeit; Test mit unterschiedlichen Browsern

• Direkte Hilfsmittel:

– Lunascape: ein Browser, bei dem man zwischen drei Maschinen umschalten kann IE (Trident)+Firefox (Gecko)+Chrome, Safari (Webkit)

– Windows: USB-portable Browser ohne Installationsnotwendigkeit (verändern keine Einstellungen): Firefox, Chrome, Opera, …

• evtl. auch Capture & Replay mit Selenium zum inhaltlichen Test

Page 35: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

583Komponentenbasierte Software-Entwicklung

6.12 JSF-Erweiterungen

• graphische Möglichkeiten in JSF recht schlicht (wesentlich besser als gezeigt!), Erweiterungsbibliotheken sinnvoll

• wesentliche frei nutzbare Komponentenframeworks:– RichFaces: http://www.jboss.org/richfaces– Primefaces: http://www.primefaces.org/

• alternative JSF-Implementierung (Standard: Mojarra):– Apache MyFaces: http://myfaces.apache.org/

• kritisch: Frameworks nur teilweise kompatibel, gilt auch für Framework mit Implementierung

• kritisch: in Details teilweise deutliche Darstellungsunterschiede in verschiedenen Browsern

• Hinweis: hier nur Ideen und notwendige Konfiguration• NetBeans bietet Nachlademöglichkeit; hier nicht genutzt um

einfacher IDE wechseln zu können

Page 36: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

584Komponentenbasierte Software-Entwicklung

Nutzung von PrimeFaces

• unterstützt JSF 2, Projekt ab November 2008

• Dokumentation war mal kostenpflichtig

• aktuell mit Support (Elite Downloads) und ohne (Community Downloads)

• Installation durch Einbinden einer einzelnen jar-Datei

• sehr viele Gestaltungsmöglichkeiten, mit Showcases gut dokumentiert

• Elemente haben oft sehr viele Parameter für Konfigurationsmöglichkeiten

• Ansatz: zu GUI-Element gehört Java-Objekt mit Konfigurationsmöglichkeiten in Java (set)

Page 37: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

585Komponentenbasierte Software-Entwicklung

Beispiel: Editorspielerei (1/4) - Managed Bean

@Named

@SessionScoped

public class Text implements Serializable {

private String inhalt;

public String getInhalt() {

return inhalt;

}

public void setInhalt(String inhalt) {

this.inhalt = inhalt;

}

}

Page 38: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

586Komponentenbasierte Software-Entwicklung

Beispiel: Editorspielerei (2/4) - index.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://xmlns.jcp.org/jsf/html"

xmlns:p="http://primefaces.org/ui">

<h:head>

<title>Editor</title>

</h:head>

<h:body>

<h:form >

<p:editor id="ed" width="600px" height="120px"

value="#{text.inhalt}" widgetVar="editor"/>

<p:commandButton update="o1,o2" async="true"

value="p Uebernehmen" onclick="editor.saveHTML();"/><br/>

<h:commandButton value="h Uebernehmen"/><br/>

<h:outputText id="o1" escape="true"

value="Inhalt: #{text.inhalt}"/><br/>

<h:outputText id="o2" escape="false"

value="Inhalt: #{text.inhalt}"/>

</h:form>

</h:body>

</html>

Page 39: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

587Komponentenbasierte Software-Entwicklung

Beispiel: Editorspielerei (3/4) - h: (Seite lädt neu)

Page 40: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

588Komponentenbasierte Software-Entwicklung

Beispiel: Editorspielerei (4/4) - p: (Aktualisierung)

Page 41: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

589Komponentenbasierte Software-Entwicklung

Anmerkungen zum Beispiel

• Normalerweise unterstützt p:commandButton Ajax direkt (nur bei p:editor Problem, deshalb Workaround mit widgetVar)

• <h:head> immer benötigt

• Generell: Genaue Analyse der oft sehr vielen Attribute einer Komponente notwendig

• Mischung von h: und p: oft (nicht immer) möglich

• Man muss mit Eigenarten der Komponenten leben (bei Großprojekten und Auswahlentscheidungen schwierig)

• detaillierte Dokumentation als PDF-Download http://www.primefaces.org/documentation

Page 42: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

590

Versionsänderung - Beispiel

• Versionswechsel 2.0.2 zu 2.2.1 führt zu anderer Darstellung• Ungleichheit p: und h: korrigiert• andere Attribute statt height="120px" nun height="120"

Komponentenbasierte Software-Entwicklung

Page 43: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

591Komponentenbasierte Software-Entwicklung

JSF - es geht noch weiter

• JSF Expression Language– einfacher Zugriff auf Maps, die Umgebungsdaten, wie

param, requests, cookies und initParam haben– Nutzung von flash-Variable als Zwischenspeicher

• Erweiterung der Expression Language • Möglichkeit GET zu nutzen (und damit Bookmarks)

– <h:button> und <h:link>• JSF hat klare Regeln wie Ressourcen verwaltet werden

(Bilder, Templates, ...) • integrierte, nutzbare JavaScript-API• Viele weitere JavaScript-Möglichkeiten (u. a. h:outputScript)• weitere Möglichkeiten des Event-Handlings, z. B. eigene

Klasse reagiert auf Event (z. B. Phasenwechsel)• Ergänzung/Erweiterung des Exception Handlings• Lokalisierung, Mehrsprachlichkeit

Page 44: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

592

7. Contexts and Dependency Injection

• klassisch Dependency Injection

• was kennen wir bereits

• CDI im Detail

– Aktivierung

– Qualifier

– Event Handling

– Objekte injizieren

– Produzenten

– Alternativen

– Interception

• Fazit

Komponentenbasierte Software-Entwicklung

Page 45: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

593

Einschub: aktueller Stand

• Sprinter ist eine klassisch aufgebaute JEE-Applikation

• wir arbeiten mit Klassen und Objekten davon

• kritisch betrachtet sind wesentliche Teile der Software nicht objektorientiert

– oftmals gibt es (pro Nutzer) genau ein Objekt von Steuerungsklassen (alles Singleton, Ausnahme Datenschicht)

– Teilprogramme rufen Methoden (?? Prozeduren) in anderen Teilprogrammen auf

• (Oracle Application Express (APEX) nutzt PL/SQL zurErstellung von Web-Applikationen)

• generell nichts Schlechtes daran!

• kritisch, Objekte müssen sich genau kennenKomponentenbasierte Software-

Entwicklung

Page 46: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

594

Ausblick auf weitere Themen

Komponentenbasierte Software-Entwicklung

Browser

Datenbank

JPA

EJBBean

Validation

CDIScope

JSFRESTful

WebService

Web Sockets

21

3

Page 47: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

595

Dependency Injection klassisch (1/2)

woher kommen Objekte für Exemplarvariablen?

• Variante 1: Werte werden als Parameter übergeben, aus denen Objekte gebaut werden (Objekt baut sich benötigte Objekte selber)

• Variante 2: Objekte werden als Referenzen übergeben

– Optimierung: Typen der Objektvariablen sind Interfaces; so konkrete Objekte leicht austauschbar

• Variante 2 heißt Dependency Injection mit get- und set-Methoden oder über Konstruktoren

Komponentenbasierte Software-Entwicklung

Page 48: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

596

Dependency Injection klassisch (2/2)

Nutzer nutzer = new Nutzer(new Inter1RealA(42)

, new Inter2RealC(43)

, new Inter3RealD("Hallo"));

eng verknüpft mit Factory Pattern

Komponentenbasierte Software-Entwicklung

Page 49: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

597

JSF nutzt bereits Dependency Injection

@Named

@SessionScoped

public class SprintController implements Serializable

@Inject

PersistenzService pers;

• @Named: Objekt steht und festen Namen zur Oberflächengestaltung zur Verfügung

• @SessionScoped: Objekt steht für die gesamte Session (auch allen anderen Objekten) zur Verfügung (Context)

• @Inject: „Umgebung gib (injiziere) mir ein zum Typen passendes Objekt“

• @PostConstruct: garantiert nach Erzeugung, vor Nutzung

• Hinweis: Annotationen stammen aus dem CDI-Paket; es gibt sehr ähnliche in JSF-Paketen (JSF ohne CDI machbar)

Komponentenbasierte Software-Entwicklung

Page 50: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

598

Ziele CDI

• Entkopplung von Objekten voneinander

– @Inject bestes Beispiel, es wird nur ein passendes Objekt „irgendwoher“ benötigt; dies besorgt CDI-Realisierung

• Vereinfachte Objekt-Kommunikation

– Beispiel: Informationen abonnieren (bekannt als PublishSubscribe oder Observer Observable)

• Vereinfachung von querschnittlich in mehreren Objekten benötigter Funktionalität

– Beispiel: Logging

• Hinzufügen von Funktionalität zu bestimmten Ereignissen ohne betroffene Methoden zu verändern

– Beispiel: Konsistenzprüfung, Benachrichtigung (Aspektorientierung)

Komponentenbasierte Software-Entwicklung

Page 51: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

599

Informationsquellen

• CDI 1.1 gehört zu JEE 7

• JSR 299: Contexts and Dependency Injection for the JavaTM EE platform, https://jcp.org/en/jsr/detail?id=299

• JSR 346: Contexts and Dependency Injection for JavaTM EE 1.1, https://jcp.org/en/jsr/detail?id=346

• JSR 365: Contexts and Dependency Injection for JavaTM 2.0 (Draft)

• Spezifikation http://www.cdi-spec.org/

– http://docs.jboss.org/cdi/spec/1.1/cdi-spec.pdf

– http://docs.jboss.org/cdi/spec/1.2/cdi-spec-1.2.pdf

• Referenzimplementierung Weld 2.0 (JBoss)

• gute Einführung: http://docs.jboss.org/weld/reference/latest/en-US/html/intro.html

Komponentenbasierte Software-Entwicklung

Page 52: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

600

NetBeans: kein Deploy on Save

gerade bei CDI ist ein vollständiges Clean & Build mit Deployfast immer sinnvoll, da Server sonst Probleme z. B. mit noch laufenden Sessions hat (Haken wegnehmen)

Komponentenbasierte Software-Entwicklung

Page 53: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

601

Aktivierung

• explizit mit beans.xml in WEB-INF –Ordner; für reine EJB-Module oder jar-Dateien im Ordner META-INF<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee

http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"

version="1.1" bean-discovery-mode="all">

</beans>

• implizit, ohne beans.xml oder mit und bean-discovery-mode="annotated", werden nur Beans mit Scope gefunden; typischerweise @Dependent für im Scope des Nutzers

• in beans.xml können (und müssen teilweise) weitere Eigenschaften spezifiziert werden

Komponentenbasierte Software-Entwicklung

Page 54: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

602

zentrales Hilfsmittel Qualifier

• Qualifier sind einfache Annotationen, mit denen gewünschte bzw. geforderte Eigenschaften spezifiziert werden können

• Normale neue Annotation mit Zusatzannotation @Qualifier...

import javax.inject.Qualifier;

@Qualifier

@Target({ElementType.TYPE, ElementType.METHOD,

ElementType.PARAMETER, ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)

public @interface Info{}

• folgende Folien: Qualifier nur erwähnt, haben dann die hier angegebene Form

Komponentenbasierte Software-Entwicklung

Page 55: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

603

Event-Model (Observer – Observable)

• auch Publish-Subscribe

• Observer sagt Bescheid, dass er vom Observable informiert werden möchte

• Observable schickt Informationen an alle Abonnenten

• Beispielaufgabe (Balkon): Informiere alle Interessierten, dass gerade ein Objekt persistiert werden soll

Komponentenbasierte Software-Entwicklung

Page 56: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

604

Event Model Übersicht (müssen nicht EJBs sein)

Komponentenbasierte Software-Entwicklung

class MeinEvent

beliebige POJO-Klasse

@Stateless

public class PersistenceService {

@Inject @Info Event<MeinEvent> event

MeinEvent me = …

event.fire(me);

Observable

@Qualifier

public @interface Info{}

Qualifier

@Stateless

public class EventConsumer {

public void empfangeMeinEvent(

@Observes @Info MeinEvent event)

{…

Observer

Page 57: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

605

Definition des Event-Objekts

• POJO mit Inhalten, die übertragen werden sollenpackage cdi.eventing;

public class MeinEvent { // POJO

private Object obj;

public MeinEvent(){

}

public Object getObj() {

return obj;

}

public void setObj(Object obj) {

this.obj = obj;

}

}

Komponentenbasierte Software-Entwicklung

Page 58: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

606

Observable – Benachrichtigen (Ausschnitt)

@Stateless

public class PersistenzService {

@Inject @Info Event<MeinEvent> event;

@Inject

private EntityManager em;

public void persist(Object object) {

MeinEvent e = new MeinEvent();

e.setObj(object);

event.fire(e);

em.persist(object);

}

Komponentenbasierte Software-Entwicklung

Page 59: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

607

Observer 1

• Durch Annotation @Info können verschiedenartige Events unterschieden werden

• beteiligte Objekte sind EJBs oder haben einen Scope (oder übernehmen Scope des nutzenden Objekts)@Stateless

public class EventConsumer {

public void empfangeMeinEvent(

@Observes @Info MeinEvent event) {

System.out.println(event.getObj());

}

}

// wenn Konsument nicht existiert, wird er erzeugt!

// nicht gewünscht: @Observes(notifyObserver=Recption.IF_EXISTS)

Komponentenbasierte Software-Entwicklung

Page 60: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

608

Observer 2

@Stateless

public class EventConsumer2 {

// Methode zeigt Machbarkeit des Ansatzes, ob dies hier

// sinnvoll, ist fraglich

public void empfangeMeinEvent(

@Observes @Info MeinEvent event) {

System.out.println(event.getObj().getClass());

if (event.getObj() instanceof Mitarbeit){

Mitarbeit m = (Mitarbeit)event.getObj();

if (m.getTaetigkeit().isEmpty()){

m.setTaetigkeit("intern");

}

}

}

}Komponentenbasierte Software-

Entwicklung

Page 61: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

609

Beispiel: neue Mitarbeit persistieren

INFO: Mitarbeit [id=0, version=0, geplanteStunden=8,

verbrauchteStunden=0, fertigstellungsgrad=0]

INFO: class entity.Mitarbeit

Komponentenbasierte Software-Entwicklung

Page 62: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

610

Konkretisierung injizierter Objekte

• bisher war immer eindeutig, welches Objekt bei @Inject genutzt wird

• häufig wird aber eine bestimmte Variante eines Objekts benötigt

• Ausgangspunkt: gibt Interface (oder abstrakte Klasse) mit mehreren Realisierungen

• der konkret gewünschte Objekttyp wird dann durch @Inject und die zusätzliche Angabe von Qualifiern festgelegt

• Beispiel: es gibt zwei verschiedene Ausgabemöglichkeiten, unterschieden durch Qualifier @LogQualifier und @SystemQualifier

Komponentenbasierte Software-Entwicklung

Page 63: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

611

Konkretisierung Übersicht

Komponentenbasierte Software-Entwicklung

interface Ausgabe {…

Angabe gewünschter Variante

@LogQualifier

public class AusgabeLog implements Ausgabe {…

@Qualifier

public @interface SystemQualifier{}

Qualifier

@Stateless

public class EventConsumer {

@Inject @LogQualifier Ausgabe aus;

@Qualifier

public @interface LogQualifier{}

Qualifier

@SystemQualifier

public class AusgabeSys implements Ausgabe {…

Interface

Realisierung

Realisierung

Page 64: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

612

Beispiel (1/4): Realisierungen 1/2

public interface Ausgabe {

public void ausgeben(String s);

}

@SystemQualifier

public class AusgabeSystem implements Ausgabe{

@Override

public void ausgeben(String s) {

System.out.println(s);

}

}

Komponentenbasierte Software-Entwicklung

Page 65: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

613

Beispiel (2/4): Realisierungen 2/2

@LogQualifier

public class AusgabeLog implements Ausgabe{

private final static Logger LOGGER = Logger

.getLogger(AusgabeLog.class.getSimpleName());

@Override

public void ausgeben(String s) {

LOGGER.log(Level.INFO, "AusgabeLog: {0}", s);

}

}

Komponentenbasierte Software-Entwicklung

Page 66: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

614

Beispiel (3/4): Auswahl der Realisierung

@Stateless

public class EventConsumer {

@Inject @LogQualifier Ausgabe aus;

public void empfangeMeinEvent(

@Observes @Info MeinEvent event) {

//System.out.println(event.getObj());

aus.ausgeben(event.getObj().toString());

}

}

• ein zentrales Logging kann man mit CDI besser durch Interceptors realisieren

• es können auch mehrere Qualifier angegeben werdenKomponentenbasierte Software-

Entwicklung

Page 67: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

615

Beispiel (4/4): Nutzung

INFO: AusgabeLog: (0) CDI einbauen

INFO: class entity.Sprint

Komponentenbasierte Software-Entwicklung

Page 68: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

616

Auswahlregeln

• Wenn Bean keinen Qualifier hat, wird er automatisch als @Default gesetzt (kann man auch hinschreiben)

• ohne benötigten Qualifier kann @Any genutzt werden

• Klassen haben ohne Scope-Angabe den Scope @Dependent, der sich dem Scope des nutzenden Objekts anpasst

Komponentenbasierte Software-Entwicklung

Page 69: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

617

Produzenten

• bisher wurde bei @Inject nach passenden Klassen gesucht und ein Objekt per Default-Konstruktor erzeugt

• Objekt-Erzeugung kann aber auch durch mit @Producesannotierte Konstruktoren, Methoden (Rückgabe-Objekt) oder direkt Exemplarvariablen erfolgen

• Konkretisierung des erzeugten Objekts wieder durch Qualifier (@Starttext, @Meldung im nächsten Beispiel)

• Beispiel zeigt kritische „Wiederverwendung“ von Qualifier

• javax.enterprise.inject.Produces nutzen

Komponentenbasierte Software-Entwicklung

Page 70: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

618

Statische Produzenten Übersicht (public vergessen)

Komponentenbasierte Software-Entwicklung

Produktions-varianten

@Qualifier

@interface Info{}

Qualifier

class Produzent {

@Produces @Meldung

private String meldung;

@Produces @Starttext

public String getLogtext() {…

@Produces @Starttext @Info

public String getLogtext2() {…

@Qualifier

@interface Meldung{}

Qualifier

class AusgabeLog {…

@Inject @Starttext @Info

private String start;

@Inject @Meldung

private String text;

Beispielnutzungen

@Qualifier

@interface Starttext{}

Qualifier

Page 71: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

619

Beispiel (1/3): Produzenten-Klasse

public class Produzent implements Serializable {

private String logtext = "logtext";

@Produces @Meldung

private String meldung;

public Produzent() { this.meldung = "Hai";}

@Produces @Starttext

public String getLogtext() {

return this.logtext;

}

@Produces @Starttext @Info

public String getLogtext2() {

System.out.println("getLogtext2");

return "2: " + this.logtext;

}

}

Komponentenbasierte Software-Entwicklung

Page 72: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

620

Beispiel (2/3): Nutzer der Produzenten

@LogQualifier

public class AusgabeLog implements Ausgabe{

private final static Logger LOGGER = Logger

.getLogger(AusgabeLog.class.getSimpleName());

@Inject @Starttext @Info private String start;

@Inject @Meldung private String text;

@Override

public void ausgeben(String s) {

//LOGGER.log(Level.INFO, "AusgabeLog: {0}", s);

LOGGER.log(Level.INFO, "{0} {1}: {2}"

, new Object[]{this.text, this.start, s});

}

}Komponentenbasierte Software-Entwicklung

Page 73: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

621

Beispiel (3/3): Beispielnutzung

INFO: getLogtext2

INFO: Hai 2: logtext: (0) Qualifier überlegen

INFO: class entity.BacklogElement

Komponentenbasierte Software-Entwicklung

Page 74: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

622

Dynamische Produzenten Übersicht

Komponentenbasierte Software-Entwicklung

Produktions-methode

Qualifier

public class Produzent{

@Produces @Aktuell

public String mach(){…

@Qualifier

public @interface Aktuell{}

public class AusgabeLog {

@Inject @Aktuell

Instance<String> datum;

public void ausgeben(…) {

datum.get()});

Beispielnutzung

Page 75: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

623

Dynamische Produktion (1/3) : Erzeugung

• wieder Produzenten-Methode mit üblichen Qualifier (also nichts Neues hier)

public class Produzent implements Serializable {

@Produces @Aktuell

public String mach(){

return new Date().toString();

}

...

Komponentenbasierte Software-Entwicklung

Page 76: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

624

Dynamische Produktion (2/3): Aufruf

@LogQualifier

public class AusgabeLog implements Ausgabe{

@Inject @Aktuell Instance<String> datum;

...

@Override

public void ausgeben(String s) {

LOGGER.log(Level.INFO, "AusgabeLog: {0} - {1}"

, new Object[]{s, datum.get()});

// LOGGER.log(Level.INFO, "{0} {1}: {2}"

// , new Object[]{this.text, this.start, s});

}

Komponentenbasierte Software-Entwicklung

Page 77: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

625

Dynamische Produktion (3/3): Beispielnutzung

INFO: AusgabeLog: (14) Fernando Alonso - Wed May 21 20:15:42 CEST 2014

INFO: AusgabeLog: (7) Kimi Räikkönen - Wed May 21 20:14:24 CEST 2014

Komponentenbasierte Software-Entwicklung

Page 78: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

626

Inject-Varianten

• statt @Inject an Exemplarvariablen zu schreiben, ist dies auch möglich:@Inject

public Konstruktor(Typ ichWerdeInjected){ …

@Inject

public void methode(Typ ichWerdeInjected){ …

• natürlich wieder Qualifier nutzbar

• weiterführend: mit @Typed an Klasse einschränken, für welche Klassen und Interfaces diese eingesetzt werden kann

Komponentenbasierte Software-Entwicklung

Page 79: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

627

Alternativen

• über Qualifier können passende Klassen genau ausgewählt werden

• z. B. zu Testzwecken, sollte diese Auswahl aber einfach änderbar sein

– hierzu wird Klasse mit @Alternative markiert

– UND muss in der beans.xml als ausgewählte Alternative angegeben werden

• durch Änderung der beans.xml sehr einfach Klassenauswahl auf Testphase oder länderspezifische Auswahlen änderbar

• mehrere Alternativen bei mehreren genutzten jars angebbar, dann Auswahl so steuerbar:

@Priority(Interceptor.Priority.APPLICATION + 10)

komplexes, sehr flexibles Auswahlsystem, wann welche Klasse genutzt wird (@Specialization)

Komponentenbasierte Software-Entwicklung

Page 80: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

628

Nutzung der Alternative (1/3): weitere Klasse

import cdi.qualifier.ausgabe.LogQualifier;

import javax.enterprise.inject.Alternative;

@Alternative

@LogQualifier

public class AusgabeLogMock implements Ausgabe{

@Override

public void ausgeben(String s) {

System.out.println("LogMock: " + s );

}

}

Komponentenbasierte Software-Entwicklung

Page 81: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

629

Nutzung der Alternative (2/3): bean.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee

http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"

bean-discovery-mode="all">

<alternatives>

<class>cdi.AusgabeLogMock</class>

</alternatives>

</beans>

Komponentenbasierte Software-Entwicklung

Page 82: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

630

Nutzung der Alternative (3/3): Nutzung

INFO: LogMock: (0) Alternativen realisieren

INFO: class entity.BacklogElement

Komponentenbasierte Software-Entwicklung

Page 83: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

631

Interceptor Übersicht

Komponentenbasierte Software-Entwicklung

unterbreche alle Methoden von

Interceptor-Benennung

@Stateless

@InterceptQualifier

public class BspKlasse {

public void meth1(…) {…

public void meth2(…) {…

@Inherited

@InterceptorBinding

public @interface InterceptQualifier{}

@InterceptQualifier

@Interceptor

public class MeinInterceptor {

@AroundInvoke

public Object logCall(

InvocationContext ctx)

throws Exception { …

Method meth = ctx.getMethod();

for (Object o: ctx.getParameters())

return ctx.proceed();

} …

bei Unterbrechung zu nutzen

<interceptors>

<class>cdi.MeinInterceptor

</class>

</interceptors>

Page 84: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

632

Interception

• Ansatz: sich in verschiedenen Methoden wiederholende Aufgaben zentral auslagern (Aspekt-Orientierung)

• (einziger) Klassiker: Logging

• Ansatz: Werden markierte Methoden oder Methoden in markierten Klassen ausgeführt, wird zunächst zum Interceptor gehörende Methode durchgeführt

• Interceptor kann auf Methode und Parameter zugreifen

• Interceptor muss Methodenausführung starten (proceed())

• Interceptor muss über bean.xml eingeschaltet werden (nur in diesem Archiv aktiv) oder @Priority-Annotation besitzen

• Interceptor benötigt eigene Art von Qualifier

• folgendes Beispiel zeigt ungewöhnliche Nutzung (auch Verstoß, dass möglichst wenig beobachtet werden soll)

Komponentenbasierte Software-Entwicklung

Page 85: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

633

Nutzung von Interception (1/5): Annotation

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

import javax.interceptor.InterceptorBinding;

//@Qualifier

@Inherited

@InterceptorBinding

@Target({ElementType.TYPE, ElementType.METHOD })

@Retention(RetentionPolicy.RUNTIME)

public @interface InterceptQualifier{}

Komponentenbasierte Software-Entwicklung

Page 86: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

634

Nutzung von Interception (2/5): Bereich festlegen

• Hier werden alle Methoden der Klasse beobachtet, man kann die Annotation auch nur für einzelne Methoden nutzen

@Stateless

@InterceptQualifier

public class EventConsumer2 {

public void empfangeMeinEvent(

@Observes @Info MeinEvent event) {

System.out.println(event.getObj().getClass());

if (event.getObj() instanceof Mitarbeit){

Mitarbeit m = (Mitarbeit)event.getObj();

if (m.getTaetigkeit().isEmpty()){

m.setTaetigkeit("intern");

}

}

}

}

Komponentenbasierte Software-Entwicklung

Page 87: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

635

Nutzung von Interception (3/5): Realisierung 1/2

@InterceptQualifier

@Interceptor

public class MeinInterceptor {

@AroundInvoke // gibt auch @AroundConstruct, @PostConstruct

public Object logCall(InvocationContext context)

throws Exception {

Method meth = context.getMethod();

System.out.println("Methode: " + meth);

/*

for (Object o : context.getParameters()) {

System.out.print(o + " ");

}

*/Komponentenbasierte Software-

Entwicklung

Page 88: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

636

Nutzung von Interception (4/5): Realisierung 2/2

MeinEvent event = (MeinEvent) context.getParameters()[0];

if (event.getObj() instanceof Mitarbeiter) {

Mitarbeiter m = (Mitarbeiter) event.getObj();

if (m.getMinr() == 999) {

m.setMinr((int) (100000 + System.nanoTime()%900000));

// m.setMinr((int) m.getId()); kann nicht gehen, da 0

}

}

return context.proceed(); // wichtig irgendwann aufrufen

}

}

Komponentenbasierte Software-Entwicklung

Page 89: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

637

Nutzung von Interception (3/4): beans.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee

http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"

bean-discovery-mode="all">

<interceptors>

<class>cdi.MeinInterceptor</class>

</interceptors>

</beans>

Komponentenbasierte Software-Entwicklung

Page 90: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

638

Nutzung von Interception (4/4): Nutzung

INFO: getLogtext2

INFO: Hai 2: logtext: (999) Clark Kent

INFO: Methode: public void

cdi.eventing.EventConsumer2.empfangeMeinEvent(cdi.eventing.

MeinEvent)

INFO: class entity.Mitarbeiter

Komponentenbasierte Software-Entwicklung

Page 91: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

639

Stereotype

• mit CDI können große Mengen von Annotationen entstehen

• häufiger haben ähnliche Klassen die gleichen Annotationen

• diese können als neue Annotation zusammengefasst werden

@RequestScoped

@Named

@MeineAnnotation

@Stereotype

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Aktion {}

• Klassen können auch mit mehreren Stereotypes (auch überlappend) annotiert werden

• Beispiel: @Model vereint @Named und @RequestScopedKomponentenbasierte Software-

Entwicklung

Page 92: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

640

Weiterführende Themen

• @Decorator, verwandt mit @Interceptor, ermöglicht Ergänzung von Funktionalität zu bestimmten Methoden

• CDI auch zu eigener Transaktionssteuerung nutzbar

Meinung: wenn JEE und EJB genutzt werden, spricht wenig für diesen Ansatz (Transaktion über mehrere Methoden)

interessant:

[Mül 14] B. Müller, JSF und JPA im Tandem, Teil 1, in: Javamagazin, 5/2014, Seiten 98-102, Software & Support Media GmbH, Frankfurt a. M. , 2014

• Auf Spezifikationsseite kann man sich über Version 1.2 informieren

Komponentenbasierte Software-Entwicklung

Page 93: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

641

Fazit

• CDI ermöglicht eine sehr große Entkopplung der Klassen voneinander

• Klassen werden so flexibler einsetzbar, evtl. Programmiermodel intuitiver

• im Beispiel wird „Balkon“ an Projekt programmiert, da @Inject und @...Scope ausreichen; nicht untypisch für klassisches JEE-Projekt

• CDI macht SW zur Zeit noch langsamer

• Annotations-Warfare-Area wird drastisch vergrößert

Komponentenbasierte Software-Entwicklung

Page 94: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

642

8. (RESTful) Web Services

• JavaScript Object Notation

• JSONP

• Idee: Web-Services

• Idee: RESTful

• erste Services

• GET, POST

• Clients

• Response

• Path-Parameter

• Aufrufparameter

• Architektur von REST-Applikationen

• Fallstudie (GET, POST, PUT, DELETE)

• Ausblick

Komponentenbasierte Software-Entwicklung

Page 95: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

643

Ausblick auf weitere Themen

Komponentenbasierte Software-Entwicklung

Browser

Datenbank

JPA

EJBBean

Validation

CDIScope

JSFRESTful

WebService

Web Sockets

21

3

Page 96: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

644

Einstieg JSON

• JavaScript Object Notation (http://json.org/)

• textuelles Austauschformat, abgeleitet aus JavaScript{ "name": "Tony Stark",

"alter": 42,

"firma": { "name": "Stark Industries",

"ort": "New York, N.Y"

},

"freunde":["Steve Rogers", "Bruce Banner"]

}

• Sammlung von

– (Name: Wert)-Paaren

– Arrays von Werten

• Werte können wieder aus beiden Elementen bestehen

Komponentenbasierte Software-Entwicklung

Page 97: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

645

Vereinheitlichung von JSON in Java

in JEE 7 ergänzt:

• JSR 353: JavaTM API for JSON Processing (23.5.2013), https://jcp.org/en/jsr/detail?id=353

• Referenzimplementierung jsonp https://jsonp.java.net/

• in Glassfish seit 4.0 enthalten

zwei zentrale APIs

• Object Model API; sehr analog zum DOM API für XML parsing

• Streaming API; sehr analog zum StAX API

• unabhängig von Programmiersprachen nutzbar

• kompakter als XML (ähnlich gut/schlecht menschenlesbar)

Komponentenbasierte Software-Entwicklung

Page 98: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

646

Beispiel: JSON-Object lesen (1/2)

public static void main(String[] args) {

String daten =

"{ \"name\": \"Tony Stark\","

+ " \"alter\": 42,"

+ " \"firma\": { \"name\": \"Stark Industries\","

+ " \"ort\": \"New York, N.Y\""

+ "},"

+ "\"freunde\":[\"Steve Rogers\", \"Bruce Banner\", 42]"

+ "}";

JsonReader reader = Json.createReader(new StringReader(daten));

JsonObject tony = reader.readObject();

reader.close();

//Set<String> namen = tony.keySet(); // geht auch

Komponentenbasierte Software-Entwicklung

Page 99: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

647

Beispiel: JSON-Objekt lesen (2/2)

System.out.println("Name : " + tony.getString("name"));

System.out.println("Alter : " + tony.getInt("alter"));

JsonObject firma = tony.getJsonObject("firma");

System.out.println("Firmenname : " + firma.getString("name"));

System.out.println("Umsatz : " + firma.getInt("umsatz", 20));

JsonArray freunde = tony.getJsonArray("freunde");

for (JsonValue freund : freunde) {

System.out.println(freund + " * " + freund.getValueType());

}

}

Name : Tony Stark

Alter : 42

Firmenname : Stark Industries

Umsatz : 20

Steve Rogers * STRING

Bruce Banner * STRING

42 * NUMBER

Default, wenn nicht da

Komponentenbasierte Software-Entwicklung

Page 100: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

648

Beispiel: JSON-Objekt von Hand erstellen

public static void main(String[] args) {

JsonObject personObject = Json.createObjectBuilder()

.add("name", "Bruce Banner")

.add("alter", 44)

.add("firma",

Json.createObjectBuilder()

.add("name", "Shield")

.add("ort", "unbekannt")

.build())

.add("freunde",

Json.createArrayBuilder()

.add("James Howlett")

.add("Ben Grimm")

.build())

.build();

System.out.println("Object: " + personObject);

}

Object:

{"name":"Bruce

Banner","alter":44,"f

irma":{"name":"Shield

","ort":"unbekannt"},

"freunde":["James

Howlett","Ben

Grimm"]}

Komponentenbasierte Software-Entwicklung

Page 101: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

649

Ausschnitt Klassendiagramm

Komponentenbasierte Software-Entwicklung

Page 102: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

650

Beispiel: Stream-Bearbeitung von JSON

// daten: siehe JSON lesen

JsonParser parser = Json

.createParser(new StringReader(daten));

while (parser.hasNext()) {

Event event = parser.next();

System.out.print(event + ": ");

switch (event) {

case KEY_NAME:

System.out.print(parser.getString());

break;

case VALUE_NUMBER:

System.out.print(parser.getInt());

break;

}

System.out.println("");

}

START_OBJECT:

KEY_NAME: name

VALUE_STRING:

KEY_NAME: alter

VALUE_NUMBER: 42

KEY_NAME: firma

START_OBJECT:

KEY_NAME: name

VALUE_STRING:

KEY_NAME: ort

VALUE_STRING:

END_OBJECT:

KEY_NAME: freunde

START_ARRAY:

VALUE_STRING:

VALUE_STRING:

VALUE_NUMBER: 42

END_ARRAY:

END_OBJECT:Komponentenbasierte Software-Entwicklung

Page 103: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

651

Binding

• Binding schafft automatische Umwandlungsmöglichkeit von A nach B und von B nach A

• ohne Binding muss die Umwandlung (marshalling) manuell erfolgen, bei Netztransport ggfls. Rückumwandlung notwendig (unmarshalling)

• Java-Objekt von und nach XML löst JAXB

• JSR 222: JavaTM Architecture for XML Binding (JAXB) 2.0, https://jcp.org/en/jsr/detail?id=222

• wichtig Umwandlungsprozess konfigurierbar

• Java-Objekt von und nach JSON noch nicht standardisiert (für JEE 8 angekündigt)

• Referenzimplementierung für Glassfish (Stand Ende 2013) ist MOXy (übersetzt JAXB-Annotationen nach JSON)

Komponentenbasierte Software-Entwicklung

Page 104: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

652

Beispiel: Vorbereitung einer Entitäts-Klasse für JSON

@XmlRootElement

public class Punkt implements Serializable {

private int x;

private int y;

public Punkt() {} // wichtig

public Punkt(int x, int y) {this.x = x; this.y = y;}

public int getX() {return x;}

public int getY() {return y;}

public void setX(int x) {this.x = x;}

public void setY(int y) {this.y = y;}

@Override

public String toString() {return "[" + x + "," + y + "]";}

}

Komponentenbasierte Software-Entwicklung

Page 105: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

653

Annotationen zur Steuerung der Übersetzung

@XmlElement(name=“rufname") // Key-Umbenennung

public String name;

@XmlTransient // nicht übertragen

public int alter;

• man beachte, dass man erhaltenes Objekt auch noch mit vorherigen Methoden modifizieren kann

• Übersetzung noch nicht standardisiert (aktuell MOXy, Teil von EclipseLink)

• da manuelle JsonObject-Erzeugung nicht sehr aufwändig und sehr flexibel, wird es gute Alternative bleiben

Komponentenbasierte Software-Entwicklung

Page 106: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

654

Hintergrund Web Services

• zentraler Wunsch: einfache Nutzung von Software über das Netz

• unabhängig wo sich ein Rechner befindet

• unabhängig von der Programmiersprache

SOAP-basierte WebServices

• jeder Service hat eindeutige Kennung (URI, Uniform Resource Identifier)

• Schnittstellenbeschreibung WSDL

• typisch: XML-basierte Kommunikationsprotokolle

• typisch: Verbindung mit SOA

• hier nicht wichtig, aber SOA ≠ SOAP ≠ Web Service

Komponentenbasierte Software-Entwicklung

Page 107: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

655

Hintergrund: Service Oriented Architecture

Service-

Verzeichnis

Service-

Anbieter

Service-

Nutzer

3. Anfragen

4. Antworten

SOAP

WSDL

HTTP

UDDI

Komponentenbasierte Software-Entwicklung

Page 108: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

656

Zwischenfazit SOA

• Vision: auf Grundlage von Geschäftsprozessmodellierungen kann individuelle Software für ein Unternehmen entstehen

• Realität: machbar, wenn alles auf einem Hersteller basiert

• Realität: UDDI hat in fast allen Projekten nicht stattgefunden (SOA ist auch Super Overhyped Acronym)

• aber: WebServices basierend auf SOAP haben als Kommunikationskonzept zentrale Bedeutung bekommen

• gilt als relativ langsam

• aber: Unternehmen nutzen es um MS-basierte Oberfläche mit JEE-realisiertem Server zu verbinden

Komponentenbasierte Software-Entwicklung

Page 109: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

657

RESTful (Representational State Transfer)

• Idee von der Interaktion zwischen Rechnern bleibt

• REST ist ein Architekturstil für verteilte Hypermedia-Systeme

• Protokoll: nutze Möglichkeiten von HTTP

– GET: lese Information (SELECT)

– POST: neue Information (INSERT)

– PUT: ändere Information (UPDATE)

– DELETE: lösche Information (DELETE)

• Klammern deuten Ähnlichkeit zu Datenbankoperationen an

• Grundlage: Dissertation Roy Fielding „Architectural Styles and the Design of Network-based Software Architectures “

• http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

Komponentenbasierte Software-Entwicklung

Page 110: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

658

Woher kommt „ Representational State Transfer“

Client fordert Information mit Hilfe einer URL an.

Eine Repräsentation der Information wird als Ergebnis zurückgegeben (z. B. in Form eines JSON-Objekts), Client hat Informationszustand.

Client nutzt Hyperlink in Ergebnis um weitere Informationen anzufordern.

Neues Ergebnis versetzt Client in einen neuen Informationszustand.

ResourceClient

http://www.scrumsprinter.de/sprint/42

{ “id”: 42,

“name”: “Prototyp”,

“elemente”: [ …

Komponentenbasierte Software-Entwicklung

Page 111: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

659

HATEOAS – saubere REST-Architektur

„Hypermedia as the Engine of Application State“

• Client kennt nur die Basis-URI des Dienstes

• Server leitet durch Informationszustände der Anwendung durch Bekanntgabe von Wahlmöglichkeiten (Hyperlinks)

• Der vollständige Informationszustand kann beim Client oder beim Server liegen, oder auch über beide verteilt sein

• HTTP-Kommunikationsprotokoll selbst bleibt zustandslos

• Grundregel: GET, PUT, DELETE sind idempotent; führen zum gleichen Ergebnis, egal wie oft sie im gleichen Informationszustand aufgerufen werden

• häufig genutzter Trick: POST auch zur partiellen Aktualisierung

Komponentenbasierte Software-Entwicklung

Page 112: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

660

Wer nutzt es (Beispiele)?

• Hinweis: Öfter wird gegen die geforderte Reinform von RESTful WebServices verstoßen, und normale Anfragemöglichkeit mit GET als RESTful oder REST-basiert bezeichnet

• Google Maps

• Google AJAX Search API

• Yahoo Search API

• Amazon WebServices

Komponentenbasierte Software-Entwicklung

Page 113: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

661

Standardisierung in Java

viele Implementierungen

• Restlet http://www.restlet.org/

• Apache CXF http://cxf.apache.org/

• Project Zero http://www.projectzero.org

• GlassFish Jersey https://jersey.dev.java.net/ (Referenz)

• JBoss RESTeasy http://www.jboss.org/resteasy/

Standardisierung für Java:

• JSR 311: JAX-RS: The JavaTM API for RESTful Web Services, https://jcp.org/en/jsr/detail?id=311 (10.10.2008)

• JSR 339: JAX-RS 2.0: The Java API for RESTful Web Services, https://jcp.org/en/jsr/detail?id=339 (24.5.2013)

Komponentenbasierte Software-Entwicklung

Page 114: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

662

JAX-RS aktivieren

• in JEE-aware Servern reicht theoretisch folgendes ausimport javax.ws.rs.ApplicationPath;

import javax.ws.rs.core.Application;

@ApplicationPath("resources")

public class ApplicationConfig extends Application {

}

• ist generell im .war-File

• sonst Konfiguration als Servlet nötig

• Beschreibung in web.xml

Komponentenbasierte Software-Entwicklung

Page 115: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

663

JAX-RS aktivieren (Alternative)

@ApplicationPath("resources")

public class ApplicationConfig extends Application {

@Override

public Set<Class<?>> getClasses() {

Set<Class<?>> resources = new java.util.HashSet<>();

try { // customize Jersey 2.0 JSON provider:

Class jsonProvider = Class

.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");

resources.add(jsonProvider);

} catch (ClassNotFoundException ex) {}

addRestResourceClasses(resources);

return resources;

}

private void addRestResourceClasses(Set<Class<?>> resources) {

resources.add(hello.HelloWorld.class);

}

}

Anbieter von Services

Komponentenbasierte Software-Entwicklung

Page 116: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

664

erste RESTful-WebServices

@Path("/helloworld")

public class HelloWorld {

public HelloWorld() { }

@GET

@Produces("text/html")

public String getHtml() {

return "<html><body><h1>Hello, World!!</h1></body></html>";

}

@GET

@Produces(MediaType.TEXT_PLAIN)

public String getText() {

return "Tach Welt";

}

}Komponentenbasierte Software-Entwicklung

Page 117: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

665

detaillierte Analyse@Path("/helloworld")

• Gibt Aufrufpfad an, hier resources/helloworld

• Pfad wird an Projektpfad, z. B. /vlRESTAnfang, angehängt

• könnte auch nur an einzelnen Methoden stehen

• kann auch zusätzlich an Methoden stehen, so dass sich der Pfad verlängert

@GET

@Produces("text/html")

• Annotationen aus javax.ws.rs

• HTTP-Befehl und Ergebnistyp (mögliche Ergebnistypen, mehrere MIME-Typen [Multipurpose Internet Mail Extension])

• nachfolgender Methodenname spielt keine Rolle!

Komponentenbasierte Software-Entwicklung

Page 118: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

666

direkter Aufruf

• bei GET ist direkter Aufruf im Browser möglich

• aber, das ist ein sehr sehr untypisches Szenario

• typisch:

– Aufruf direkt aus einer Web-Seite, meist mit JavaScript

– Aufruf aus anderer Software heraus mit Mitteln der jeweiligen Programmiersprache (z. B. java.net.URL)

• NetBeans: kein Haken bei „Display Browser on Run“

Komponentenbasierte Software-Entwicklung

Page 119: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

667

Detaillierte Analyse mit cURL

• generell jedes Programm zur Erzeugung von HTTP-Aufrufen und Analyse der Ergebnisse geeignet

• Kommando-Zeile mit cURLhttp://curl.haxx.se/download.html

• Für etwaige Parameter muss auch URL in Anführungsstrichen stehen

• viele Browser unterstützen direkt bei solchen Tests

Komponentenbasierte Software-Entwicklung

Page 120: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

668

Nutzung automatischen Marshallings - GET

• verschiedene Rückgabetypen bedienbar (praktisch sinnvoll?)@GET

@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_JSON})

public Punkt getJSon2() {

return new Punkt(42,43); // war @XMLRootElement annotiert

}

Komponentenbasierte Software-Entwicklung

Page 121: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

669

Nutzung automatischen Unmarshallings - POST

@POST

@Produces(MediaType.TEXT_PLAIN)

@Consumes(MediaType.APPLICATION_JSON)

public String postit(Punkt p){

System.out.println(p);

return "ok";

}

• weitere Parameter im JSON-Objekt führen zu Fehlern

Komponentenbasierte Software-Entwicklung

Page 122: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

670

zentrale Klassen Client und Response

• RESTful Web Services werden typischerweise aus anderer Software aufgerufen

• dies ist natürlich auch in Java möglich; vor JAX-RS 2.0 aber proprietäre Lösungen der Anbieter

• https://jersey.java.net/download.html

• jetzt Klasse javax.ws.rs.client.Client

• Bei der Nutzung von RESTful Web Services können verschiedene Klassen als Typen für Parameter und Rückgabe genutzt werden

• Hilfreich ist Klasse javax.ws.rs.core.Response

• Server erzeugt Response-Objekt

• Client kann problemlos Response-Objekt lesen

• Response ist ein Stream, muss auch geschlossen werden

Komponentenbasierte Software-Entwicklung

Page 123: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

671

Hilfsmethode zur genaueren Analyse von Response

private void details(Response res) {

System.out.println("-----------------\n"

+ "AllowedMethods : " + res.getAllowedMethods() + "\n"

+ "Entity Class: " + res.getEntity().getClass() + "\n"

+ "Language : " + res.getLanguage() + "\n"

+ "Location : " + res.getLocation() + "\n"

+ "Mediatype : " + res.getMediaType() + "\n"

+ "Links : " + res.getLinks() + "\n"

+ "Status : " + res.getStatus() + "\n"

+ "Date : " + res.getDate() + "\n"

+ "Class : " + res.getClass() + "\n"

+ "Inhalt : " + res.readEntity(String.class));

res.close();

}

Komponentenbasierte Software-Entwicklung

Page 124: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

672

Kleine Beispiele (1/7)

• Anmerkung: Zeigt Service-Nutzung, zeigt nichts von RESTpublic class ClientAnalyse {

private Client client;

private WebTarget userTarget;

public ClientAnalyse() {

Client client = ClientBuilder.newClient();

userTarget = client

.target("http://localhost:8080/vlRESTAnfang"

+ "/resources/helloworld");

}

Komponentenbasierte Software-Entwicklung

Page 125: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

673

Kleine Beispiele (2/7)

public void analyse1() {

Response res = userTarget.request("text/html").get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$2

Language : null

Location : null

Mediatype : text/html

Links : []

Status : 200

Date : Fri Dec 18 15:39:22 CET 2015

Class : class org.glassfish.jersey.client.InboundJaxrsResponse

Inhalt : <html lang="en"><body><h1>Hello, World!!</h1></body></html>

Komponentenbasierte Software-Entwicklung

Page 126: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

674

Kleine Beispiele (3/7)

public void analyse1() {

Response res = userTarget.request(MediaType.TEXT_PLAIN).get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$2

Language : null

Location : null

Mediatype : text/plain

Links : []

Status : 200

Date : Wed May 14 18:55:35 CEST 2014

Class : class org.glassfish.jersey.client.ScopedJaxrsResponse

Inhalt : <html lang="en"><body><h1>Hello, World!!</h1></body></html>

Komponentenbasierte Software-Entwicklung

Page 127: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

675

Kleine Beispiele (4/7)

public void analyse3() {

Response res = userTarget

.request(MediaType.APPLICATION_JSON).get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1

Language : null

Location : null

Mediatype : application/json

Links : []

Status : 200

Date : Wed May 14 18:55:35 CEST 2014

Class : class org.glassfish.jersey.client.ScopedJaxrsResponse

Inhalt : {"x":42,"y":43}

Komponentenbasierte Software-Entwicklung

Page 128: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

676

Kleine Beispiele (5/7)

public void analyse4() {

Response res = userTarget.request(MediaType.TEXT_XML).get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1

Language : null

Location : null

Mediatype : text/xml

Links : []

Status : 200

Date : Wed May 14 19:08:13 CEST 2014

Class : class org.glassfish.jersey.client.ScopedJaxrsResponse

Inhalt : <?xml version="1.0" encoding="UTF-8"

standalone="yes"?><punkt><x>42</x><y>43</y></punkt>

Komponentenbasierte Software-Entwicklung

Page 129: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

677

Kleine Beispiele (6/7)

public void analyse5() {

Builder buil = this.userTarget.request(MediaType.TEXT_PLAIN);

Entity e = Entity.entity(new Punk(3, 4)

, MediaType.APPLICATION_JSON);

System.out.println(e + " : " + e.getEntity());

String res = buil.post(e, String.class);

System.out.println(res);

}

javax.ws.rs.client.Entity@52aa911c : [3,4]

ok

• Anmerkung: Klasse Punk wie Punkt, sogar ohne XMLRootElement-Annotation , aber Serializable

Komponentenbasierte Software-Entwicklung

Page 130: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

678

Kleine Beispiele (7/7)

public void analyse6() {

Builder buil = this.userTarget.request(MediaType.TEXT_PLAIN);

Entity e = Entity.json(new Punk(2,3));

System.out.println(e + " : " + e.getEntity());

String res = buil.post(e, String.class);

System.out.println(res);

}

Entity{entity=[2,3], variant=Variant[mediaType=application/json,

language=null, encoding=null], annotations=[]} : [2,3]

ok

• Klasse Entity bietet einige Marshalling-Methoden

Komponentenbasierte Software-Entwicklung

Page 131: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

679

flexible Dienststrukturen

• generell soll man aus Antworten auf weitere Abfragemöglichkeiten schließen können

• /helloworld/kunden/

Frage nach Kunden: Sammlung der Namen aller Kunden

• /helloworld/kunden/Hoeness/

Frage nach Kunden mit Namen: alle Eigenschaften des Kunden

• /helloworld/kunden/Hoeness/konten

Frage nach Konten eines benannten Kunden: Sammlung aller Konten des Kunden

• /helloworld/kunden/Hoeness/konten/42

Frage nach Kontonummer eines benannten Kunden: alle Eigenschaften des Kontos dieses Kunden

Komponentenbasierte Software-Entwicklung

Page 132: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

680

Beispiel: Umsetzung von Pfaden (1/4)

@Path("helloworld")

public class HelloWorld {

// Kundenname, Sammlung von Konten (Nummer, Betrag)

private Map<String, Map<Integer, Long> > kunden;

public HelloWorld() {

// zufaellige Beispieldaten

Map<Integer,Long> tmp = new HashMap<>();

tmp.put(42,32000000L);

kunden = new HashMap<>();

kunden.put("Hoeness", tmp);

}

Komponentenbasierte Software-Entwicklung

Page 133: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

681

Beispiel: Umsetzung von Pfaden (2/4)

@GET

@Produces(MediaType.APPLICATION_JSON)

@Path("/kunden/{user}/konten/{id}")

public JsonObject getKontostand(

@PathParam("user") String user

, @PathParam("id") int id) {

JsonObjectBuilder erg = Json.createObjectBuilder();

Map<Integer,Long> kunde = kunden.get(user);

if(kunde == null){

return erg.add("fehler", "kein Kunde").build();

}

Long summe = kunde.get(id);

if(summe == null){

return erg.add("fehler", "kein Konto").build();

}

return erg.add("summe", summe).build();

}Komponentenbasierte Software-

Entwicklung

Page 134: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

682

Beispiel: Umsetzung von Pfaden (3/4)

public static void main(String[] a){

String[] verdaechtig = {"Rummenigge", "Hoeness"};

int[] nummern = {42,43};

Client client = ClientBuilder.newClient();

for(String v:verdaechtig){

for (int n:nummern){

WebTarget target = client.target("http://localhost:8080"

+ "/vlRESTAnfang/resources/helloworld/kunden/"

+ v + "/konten/" + n);

JsonObject erg = target

.request(MediaType.APPLICATION_JSON)

.get(JsonObject.class);

System.out.println(erg);

}

}

}

Komponentenbasierte Software-Entwicklung

Page 135: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

683

Beispiel: Umsetzung von Pfaden (4/4)

{"fehler":"kein Kunde"}

{"fehler":"kein Kunde"}

{"summe":32000000}

{"fehler":"kein Konto"}

Komponentenbasierte Software-Entwicklung

Page 136: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

684

Umsetzung von Pfaden

@Path("/kunden/{user}/konten/{id}")

• Einbau von Pfadvariablen, auf die in Parameterliste mit @PathParam("user") zugegriffen werden kann

• einfache Java-Typen, typischerweise int, long, String nutzbar; Konvertierung automatisch

• Pfadvariablen in der Klassenannotation können dann in jedem Methodenkopf genutzt werden

• Pfadvariablen können in @Path doppelt vorkommen und müssen dann gleichen Wert bei Nutzung haben

• im Hinterkopf: wenn HTTPS, dann auch User-Token so übertrag- und später prüfbar (Sicherheit)

• im Hinterkopf: individueller Wert für jeden Nutzer, der E-Mail mit so einem Link erhält

Komponentenbasierte Software-Entwicklung

Page 137: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

685

Externer Service zur Analyse von IPs (1/4)

private static void zeigeJsonObjekt(JsonObject js){

for(String key:js.keySet()){

System.out.println(key+ ": " + js.get(key));

}

}

public static void main(String[] s){

String SERVICE = "http://freegeoip.net/json";

Client client = ClientBuilder.newClient();

WebTarget wt = client.target(SERVICE);

Invocation.Builder invoc = wt.request();

JsonObject ergebnis = invoc.get(JsonObject.class);

zeigeJsonObjekt(ergebnis);

zeigeJsonObjekt(client.target(SERVICE+"/www.bild.de")

.request().get(JsonObject.class));

}Komponentenbasierte Software-Entwicklung

Page 138: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

686

Externer Service zur Analyse von IPs (2/4)

ip: "84.155.86.93"

country_code: "DE"

country_name: "Germany"

region_code: "NI"

region_name: "Lower Saxony"

city: "Neuenkirchen"

zip_code: "49586"

time_zone: "Europe/Berlin"

latitude: 52.4167

longitude: 7.85

metro_code: 0

ip: "72.247.9.43"

country_code: "US"

country_name: "United States"

region_code: "MA"

region_name: "Massachusetts"

city: "Cambridge"

zip_code: "02142"

time_zone: "America/New_York"

latitude: 42.3626

longitude: -71.0843

metro_code: 506

Komponentenbasierte Software-Entwicklung

Page 139: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

687

Externer Service zur Analyse von IPs (3/4)

public static void main(String[] st){

Client client = ClientBuilder.newClient();

WebTarget wt = client.target("http://freegeoip.net/json");

Invocation.Builder invoc = wt.request();

Response ergebnis = invoc.get();

System.out.println(ergebnis);

ergebnis.bufferEntity(); // sonst Fehler bei 42

System.out.println(ergebnis.getEntity());

for(String s:ergebnis.getHeaders().keySet()){

System.out.println(s +": " + ergebnis.getHeaders().get(s));

}

System.out.println(ergebnis.readEntity(JsonObject.class));

System.out.println(ergebnis.getEntity().getClass()); //42

ergebnis.close();

}Komponentenbasierte Software-

Entwicklung

Page 140: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

688

Externer Service zur Analyse von IPs (4/4)

ScopedJaxrsResponse{ClientResponse{method=GET,

uri=http://freegeoip.net/json, status=200, reason=OK}}

java.io.ByteArrayInputStream@6d420a24

Date: [Wed, 14 May 2014 17:48:10 GMT]

Access-Control-Allow-Origin: [*]

Content-Length: [222]

Content-Type: [application/json]

{"ip":"93.196.192.46","country_code":"DE","country_name":"Germany","

region_code":"07","region_name":"Nordrhein-

Westfalen","city":"Hopsten","zipcode":"","latitude":52.3833,"longitu

de":7.6167,"metro_code":"","area_code":""}

class java.io.ByteArrayInputStream

Komponentenbasierte Software-Entwicklung

Page 141: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

689

Übergabe von Aufrufparametern (1/2)

@GET

@Produces(MediaType.APPLICATION_JSON)

@Path("/rechnen")

public JsonObject machMathe(

@QueryParam("op1") int op1,

@QueryParam("op2") int op2,

@DefaultValue("plus")

@QueryParam("operator") String operator) {

JsonObjectBuilder erg = Json.createObjectBuilder();

if(operator.equals("minus")){

return erg.add("operator", operator)

.add("ergebnis", (op1-op2)).build();

}

return erg.add("operator", "plus")

.add("ergebnis", (op1+op2)).build();

}

Komponentenbasierte Software-Entwicklung

Page 142: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

690

Übergabe von Aufrufparametern (2/2)

Komponentenbasierte Software-Entwicklung

Page 143: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

691

Dienstnutzung mit Aufrufparametern (1/2)

public static void main(String[] s) {

String SERVICE

= "http://maps.googleapis.com/maps/api/geocode/json";

Client client = ClientBuilder.newClient();

WebTarget wt = client.target(SERVICE +

"?address=Quakenbrueck&sensor=false");

Invocation.Builder invoc = wt.request();

JsonObject ergebnis = invoc.get(JsonObject.class);

System.out.println(ergebnis);

JsonObject details = ((JsonArray)ergebnis.get("results"))

.getJsonObject(0);

JsonObject position= (JsonObject)

((JsonObject)details.get("geometry")).get("location");

System.out.println(position);

}

Komponentenbasierte Software-Entwicklung

Page 144: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

692

Dienstnutzung mit Aufrufparametern (2/2)

{"results":[{"address_components":[{"long_name":"Quakenbrück","

short_name":"Quakenbrück","types":["locality","political"]},{"l

ong_name":"Lower

Saxony","short_name":"NDS","types":["administrative_area_level_

1","political"]},{"long_name":"Germany","short_name":"DE","type

s":["country","political"]}],"formatted_address":"Quakenbrück,

Germany","geometry":{"bounds":{"northeast":{"lat":52.6967289,"l

ng":8.0344312},"southwest":{"lat":52.65917049999999,"lng":7.903

767999999999}},"location":{"lat":52.675599,"lng":7.950777699999

999},"location_type":"APPROXIMATE","viewport":{"northeast":{"la

t":52.6967289,"lng":8.0344312},"southwest":{"lat":52.6591704999

9999,"lng":7.903767999999999}}},"place_id":"ChIJqfqve3Zpt0cRIqf

jZXu8LGw","types":["locality","political"]}],"status":"OK"

{"lat":52.675599,"lng":7.950777699999999}

Komponentenbasierte Software-Entwicklung

Page 145: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

693

Aufgabe

Sprinter soll um eine RESTful-Schnittstelle ergänzt werden,

• mit der von außen auf Sprints zugegriffen werden kann,

• die nur eine Teilmenge der Daten der Sprints sieht,

• die neue Sprints anlegen kann,

• die Sprints editieren kann,

• die Sprints löschen kann

• Entscheidung: Ergänze Programm um RESTful Webservices

• Schnittstelle wird in neuem Projekt genutzt (das zum einfacheren Verständnis eine JSF-Oberfläche bekommt)

Komponentenbasierte Software-Entwicklung

Page 146: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

694

Nutzungsszenario

• Links nicht ausimplementiert

Komponentenbasierte Software-Entwicklung

Page 147: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

695

Architektur: hierarchischer Aufbau

Resource POST(CREATE)

GET(READ)

PUT(UPDATE)

DELETE(DELETE)

/sprints erzeugt neuen Sprint

Übersicht über alle Sprints

Aktualisiere alle Sprints (oder weglassen)

alle Sprints löschen

/sprints/42 Fehler! Zeige Sprint mit id 42

wenn Sprint mit id 42 existiert, dann aktualisieren, (sonst Fehler ?)

Lösche den Sprint mit id42

Hinweise: noch sauberer wäre /sprint/42 (Einzahl)graue Felder nicht realisiert

Komponentenbasierte Software-Entwicklung

Page 148: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

696

Einordnung SprintRestController (Server)

Komponentenbasierte Software-Entwicklung

Page 149: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

697

Client (minimal)

Komponentenbasierte Software-Entwicklung

Page 150: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

698

Vorbereitung im Server

@Stateless // oder @Singleton

@Path("")

public class SprintRestController implements Serializable{

@Inject

private PersistenzService pers;

@Context

private UriInfo uriInfo; // später genauer

private SimpleDateFormat formatter

= new SimpleDateFormat("dd.MM.yyyy");

public SprintRestController() {

}

Komponentenbasierte Software-Entwicklung

Page 151: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

699

Hilfsmethode zum Sprint einpacken

private JsonObject jsonSprint(Sprint s, boolean einzeln) {

String idzeigen = (einzeln) ? "" : "" + s.getId();

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("id", s.getId())

.add("motto", s.getMotto())

.add("starttermin", formatter.format(s.getStarttermin()))

.add("endtermin", formatter.format(s.getEndtermin()))

.add("geplanterAufwand", s.getGeplanterAufwand())

.add("farbe", s.color())

.add("link", uriInfo.getAbsolutePathBuilder()

.path(idzeigen + "/backlogElemente")

.build().getPath());

return js.build();

}

Komponentenbasierte Software-Entwicklung

Page 152: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

700

GET /sprints (1/2)

@GET

@Produces({MediaType.APPLICATION_JSON})

@Path("/sprints")

public JsonObject getSprints(

@DefaultValue("-1") @QueryParam("von") int von,

@DefaultValue("-1") @QueryParam("bis") int bis) {

List<Sprint> alle = pers.findAllSprint();

if (von < 0 || von >= alle.size()) {

von = 0;

}

if (bis < 0 || bis >= alle.size()) {

bis = alle.size() - 1;

}

Komponentenbasierte Software-Entwicklung

Page 153: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

701

GET /sprints (2/2)

JsonArrayBuilder elemente = Json.createArrayBuilder();

for (int i = von; i <= bis; i++) {

elemente.add(jsonSprint(alle.get(i), false));

}

return Json.createObjectBuilder()

.add("sprints", elemente)

.build();

}

Komponentenbasierte Software-Entwicklung

Page 154: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

702

Client – Vorbereitung (1/2)

• Client braucht keine echte Datenhaltung

• Ansatz: Daten lokal in SessionScope halten (für kleinere Datenmengen ok

@Named

@SessionScoped

public class SprintController implements Serializable {

private Client client;

private List<Map<String, Object>> sprints;

private final static String[] keys = {"id", "motto"

, "starttermin", "endtermin", "geplanterAufwand"

, "link", "farbe"};

private final static String SPRINTS

= "http://localhost:8080/Sprinter/resources/sprints";

private final static String HOME = "index";

Komponentenbasierte Software-Entwicklung

Page 155: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

703

Client – Vorbereitung (2/2)

• eine Variable pro Eigenschaft mit get und setenum Status {BASIC, EDIT;}

private long id;

private String motto;

private Date starttermin;

private Date endtermin;

private int geplanterAufwand;

private Status modus;

private String meldung = ""; // Statusmeldung ohne Voodoo

SimpleDateFormat formatter

= new SimpleDateFormat("dd.MM.yyyy");

public SprintController() {

}

Komponentenbasierte Software-Entwicklung

Page 156: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

704

Client – Initialisierung (1/2)

@PostConstruct

public void init() {

this.modus = Status.BASIC;

this.client = ClientBuilder.newClient();

WebTarget wt = client.target(SPRINTS);

Invocation.Builder buil = wt

.request(MediaType.APPLICATION_JSON);

JsonObject ergebnis = buil.get(JsonObject.class);

JsonArray array = ergebnis.getJsonArray("sprints");

this.sprints = new ArrayList<Map<String, Object>>();

for (JsonValue val : array) {

JsonObject js = (JsonObject) val;

// speichert einen String als Attribut/Wert-Paar

Map<String, Object> werte = new HashMap<String, Object>();

Komponentenbasierte Software-Entwicklung

Page 157: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

705

Client – Initialisierung (2/2)

for (String k : keys) {

werte.put(k, js.get(k));

}

this.sprints.add(werte);

}

this.motto = "";

this.starttermin = null;

this.endtermin = null;

this.geplanterAufwand = 0;

} in älteren Versionen überflüssige " entfernen for (String k : keys) {

Object tmp = js.get(k);

String txt = tmp.toString();

if(txt.startsWith("\"") && txt.endsWith("\"") && txt.length() > 1){

tmp = txt.substring(1, txt.length()-1);

}

werte.put(k, tmp);

Komponentenbasierte Software-Entwicklung

Page 158: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

706

Erfolgloses Löschen möglich

• vom anderen Nutzer gelöscht oder modifiziert

• Idempotent wäre, diesen Fehler zu ignorieren (ist gelöscht)

Komponentenbasierte Software-Entwicklung

Page 159: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

707

Server Action loeschen

@DELETE

@Path("/sprints/{id}")

public JsonObject loeschen(@PathParam("id") long id) {

pers.removeSprint(id);

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("status", "geloescht");

return js.build();

}

Komponentenbasierte Software-Entwicklung

Page 160: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

708

Client löschen

public String loeschen(Object sid) {

System.out.println("loeschen: " + sid);

WebTarget wb = client.target(SPRINTS + "/" + sid);

Invocation.Builder build = wb

.request(MediaType.APPLICATION_JSON);

try {

JsonObject ergebnis = build.delete(JsonObject.class);

this.meldung = "loeschen erfolgreich: " + ergebnis;

} catch (Exception e) {

this.meldung = "loeschen gescheitert: " + e;

}

init();

this.modus = Status.BASIC;

return HOME;

}Komponentenbasierte Software-

Entwicklung

Page 161: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

709

Neuer Sprint – Server (1/2)

@POST

@Produces(MediaType.APPLICATION_JSON)

@Consumes(MediaType.APPLICATION_JSON)

@Path("/sprints")

public JsonObject hinzufuegen(JsonObject jo) {

Sprint sprint = new Sprint();

sprint.setMotto(jo.getString("motto"));

sprint.setGeplanterAufwand(jo.getInt("geplanterAufwand"));

SimpleDateFormat formatter

= new SimpleDateFormat("dd.MM.yyyy");

try {

sprint.setStarttermin(formatter

.parse(jo.getString("starttermin")));

Komponentenbasierte Software-Entwicklung

Page 162: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

710

Neuer Sprint – Server (2/2)

sprint.setEndtermin(formatter

.parse(jo.getString("endtermin")));

} catch (ParseException ex) {

return null;

}

pers.persist(sprint);

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("link"

, uriInfo.getAbsolutePathBuilder()

.path(sprint.getId() + "/backlogElemente")

.build().getPath());

return js.build();

}

Komponentenbasierte Software-Entwicklung

Page 163: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

711

Neuer Sprint – Client Aktion uebernehmen (1/4)

public String uebernehmen() {

// Validerung des Clients muss dieser regeln

if (this.starttermin == null || this.endtermin == null){

this.meldung = "Start- und Endtermin angeben!";

return HOME;

}

if (this.starttermin.compareTo(this.endtermin) > 0){

this.meldung = "Endtermin nicht vor Starttermin";

return HOME;

}

Komponentenbasierte Software-Entwicklung

Page 164: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

712

Neuer Sprint – Client Aktion uebernehmen (2/4)

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("motto", this.motto)

.add("starttermin", formatter.format(this.starttermin))

.add("endtermin", formatter.format(this.endtermin))

.add("geplanterAufwand", this.geplanterAufwand);

if (this.modus.equals(Status.BASIC)) {

neuerSprint(js);

}

if (this.modus.equals(Status.EDIT)) {

editiereSprint(js);

}

init();

this.modus = Status.BASIC;

return HOME;

}Komponentenbasierte Software-

Entwicklung

Page 165: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

713

Neuer Sprint – Client Aktion uebernehmen (3/4)

private void neuerSprint(JsonObjectBuilder js){

WebTarget wb = client.target(SPRINTS);

Invocation.Builder build = wb

.request(MediaType.APPLICATION_JSON);

Entity entity = Entity.entity(js.build()

, MediaType.APPLICATION_JSON);

try {

JsonObject ergebnis = build.post(entity, JsonObject.class);

this.meldung = "einfuegen erfolgreich: " + ergebnis;

} catch (Exception e) {

this.meldung = "einfuegen gescheitert: " + e;

}

}

Komponentenbasierte Software-Entwicklung

Page 166: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

714

Sprint editieren – Server (1/2)

@PUT

@Produces(MediaType.APPLICATION_JSON)

@Consumes(MediaType.APPLICATION_JSON)

@Path("/sprints/{id}")

public JsonObject aktualisieren( @PathParam("id") long id

, JsonObject jo) {

Sprint sprint = pers.findSprint(id);

sprint.setMotto(jo.getString("motto"));

sprint.setGeplanterAufwand(jo.getInt("geplanterAufwand"));

try {

sprint.setStarttermin(formatter

.parse(jo.getString("starttermin")));

sprint.setEndtermin(formatter

.parse(jo.getString("endtermin")));

Komponentenbasierte Software-Entwicklung

Page 167: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

715

Sprint editieren – Server (2/2)

} catch (ParseException ex) {

return null;

}

pers.merge(sprint);

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("link"

, uriInfo.getAbsolutePathBuilder()

.path("/backlogElemente").build().getPath());

return js.build();

}

Komponentenbasierte Software-Entwicklung

Page 168: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

716

Editiere Sprint – Client Aktion uebernehmen (4/4)

private void editiereSprint(JsonObjectBuilder js) {

WebTarget wb = client.target(SPRINTS + "/" + this.id);

Invocation.Builder build = wb

.request(MediaType.APPLICATION_JSON);

js.add("id", id);

Entity entity = Entity.entity(js.build()

, MediaType.APPLICATION_JSON);

try {

JsonObject ergebnis = build.put(entity, JsonObject.class);

this.meldung = "aktualisieren erfolgreich: " + ergebnis;

} catch (Exception e) {

this.meldung = "aktualisieren gescheitert: " + e;

}

}

Komponentenbasierte Software-Entwicklung

Page 169: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

717

UriInfo (1/2)

@Path("ana")

@Stateless

public class Analyse {

@Context

private UriInfo uriInfo;

private final static Logger LOGGER = Logger

.getLogger(Analyse.class.getSimpleName());

@GET

@Produces(MediaType.TEXT_PLAIN)

public String getText() {

LOGGER.info("in getText");

LOGGER.info(this.uriInfo.getAbsolutePath().toString());

Komponentenbasierte Software-Entwicklung

Page 170: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

718

UriInfo (2/2)

LOGGER.info(this.uriInfo.getPath());

LOGGER.info(this.uriInfo.getRequestUri().toString());

for (String s:this.uriInfo.getQueryParameters().keySet()){

LOGGER.info(s+ ": "

+ this.uriInfo.getQueryParameters().get(s));

}

return "hai";

}

INFO: in getText

INFO: http://localhost:8080/resources/ana

INFO: /ana

INFO: http://localhost:8080/resources/ana?x=Hai&text=42

INFO: text: [42]

INFO: x: [Hai]

Komponentenbasierte Software-Entwicklung

Page 171: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

719

WADL (1/3)

• Web Application Description Language

• XML-basierte Beschreibung angebotener Dienste

• generell soll HTTP-Befehl OPTIONS genutzt werden, um Übersicht zu erhalten

• Alle möglichen Dienste mit Parametern werden aufgeführt

• Dienstbeschreibungen können aus Annotation generiert werden

• Alternativ kann @OPTIONS-annotierte Methode realisiert werden (z. B. um Ausgabe zu verhindern)

• Bedeutung eher gering, für Werkzeuge basierend auf WADL-Services interessant; erkennen so Aktualisierungen

Komponentenbasierte Software-Entwicklung

Page 172: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

720

WADL (2/3) - Beispielmethode

@GET

@Produces("text/html")

public String getHtml() {

return "<html><body>Hello, World!!</body></html>";

}

<resources base="http://localhost:8080/resources/">

<resource path="helloworld">

<method id="getHtml" name="GET">

<response>

<representation mediaType="text/html"/>

</response>

</method>

...

Komponentenbasierte Software-Entwicklung

Page 173: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

721

WADL (3/3) – Beispiel aus Sprinter

<resources base="http://localhost:8080/Sprinter/resources/">

<resource path="sprints">

<method id="getSprints" name="GET">

<request>

<param xmlns:xs="http://www.w3.org/2001/XMLSchema"

name="von"

style="query" type="xs:int" default="-1"/>

<param xmlns:xs="http://www.w3.org/2001/XMLSchema"

name="bis"

style="query" type="xs:int" default="-1"/>

</request>

<response>

<representation mediaType="application/json"/>

</response>

</method>

<method id="hinzufuegen" name="POST">

<request>

<representation mediaType="application/json"/>

</request>

<response>

<representation mediaType="application/json"/>

</response>

Komponentenbasierte Software-Entwicklung

Page 174: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

722

@FormParam

<form action="http://vfl.de/mitglieder" method="post">

<p>

Vorname: <input type="text" name="vorname"><br>

Nachname: <input type="text" name="nachname"><br>

<input type="submit" value="Send">

</p>

</form>

@Path("/mitglieder")

@Consumes(Mediatype.APPLICATION_FORM_URLENCODED)

public class CustomerResource {

@POST

public void createCustomer(

@FormParam(“vorname") String vorname

, @FormParam(“nachname") String nachname) {

...

}

ermöglicht die Übernahme von Parametern einer POST-Anfrage eines HTML-Formulars

Komponentenbasierte Software-Entwicklung

Page 175: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

723

Response.Status (gibt evtl. passende Exceptions)public enum Status {

OK(200, "OK"), CREATED(201, "Created"),

ACCEPTED(202, "Accepted"),

NO_CONTENT(204, "No Content"),

MOVED_PERMANENTLY(301, "Moved Permanently"),

SEE_OTHER(303, "See Other"),

NOT_MODIFIED(304, "Not Modified"),

TEMPORARY_REDIRECT(307, "Temporary Redirect"),

BAD_REQUEST(400, "Bad Request"),

UNAUTHORIZED(401, "Unauthorized"),

FORBIDDEN(403, "Forbidden"),

NOT_FOUND(404, "Not Found"),

NOT_ACCEPTABLE(406, "Not Acceptable"),

CONFLICT(409, "Conflict"), GONE(410, "Gone"),

PRECONDITION_FAILED(412, "Precondition Failed"),

UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),

INTERNAL_SERVER_ERROR(500, "Internal Server Error"),

SERVICE_UNAVAILABLE(503, "Service Unavailable");

Komponentenbasierte Software-Entwicklung

Page 176: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

724

Weiterführend (1/2)

• asynchron@POST

@Asynchronous public void bearbeite(

@Suspended AsyncResponse ar, Daten daten)

• reguläre Ausdrücke in Path, @Path("{id : .+}")

komplexe Auswertungsregeln, was, wenn mehrere Möglichkeiten an Pfaden existieren

• HEAD: nimmt typischerweise erste GET und gibt statt Ergebnis nur Header und Response-Code zurück

• MIME-Types können sehr detailliert sein, generelltype/subtype;name=value;name=value...

@Consumes("application/xml;charset=utf-8")

Komponentenbasierte Software-Entwicklung

Page 177: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

725

Weiterführend (2/2)

• JAX-RS-Annotationen können auch nur in Interfaces ausgelagert werden

• Matrix-Parameter (Attribute) behandelbarhttp://beispiel.spieler.de/vfl;typ=Sturm/2015

• Nutzung von Header-Parametern @HeaderParampublic String get(@HeaderParam("Referrer") String

aufrufer) {

public String get(@Context HttpHeaders headers) {

• Cookie-Nutzung public String get(@CookieParam(“minr") int minr)

• genauere Analyse vom ResponseBuilder.status(.)

• Einbindung von Bean Validation

• …

Komponentenbasierte Software-Entwicklung

Page 178: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

726

Literatur

• (Standard-Links sind im Text)

• [Bur14] B. Burke, RESTful Java with JAX-RS 2.0, O‘Reilly, Sebastopol (CA), USA, 2014

• http://www.oracle.com/technetwork/articles/java/jaxrs20-1929352.html

Komponentenbasierte Software-Entwicklung

Page 179: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

727

9. WebSockets

• WebSockets

– Verbreitung

– zentrale Nachrichten

– Realisierung eines Chats

– Encoder

– Decoder

• Bedeutung von JavaScript

basiert teilweise auf: [Dit14] A. Ditler, Prototypische Realisierung eines Echtzeit-Webchats als Crossplattform-Applikation auf Basis von Websockets, Hochschule Osnabrück, Bachelorarbeit, 2014

Komponentenbasierte Software-Entwicklung

Page 180: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

728

WebSockets - Motivation

• HTTP erlaubt nur die Beantwortung von Client-Anfragen

• ohne Erweiterung keine Möglichkeit, dass der Server den Client nachträglich ohne erneute Anfrage informiert

• nur mit Workaround z. B. AJAX und Long-Polling möglich

• WebSockets erlauben die bidirektionale Kommunikation zwischen Client und Server

• allgemein: The WebSocket API, W3C Candidate Recommendation, 20.09.2012, http://www.w3.org/TR/websockets/

• standardisiert in Java: JSR 356: JavaTM API for WebSocket, https://jcp.org/en/jsr/detail?id=356

Komponentenbasierte Software-Entwicklung

Page 181: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

729

Verbreitung (1/2)

• aktuell wird Ansatz in vielen Projekten evaluiert, Nutzung hängt von Zielplattformen ab

• Anmerkung: Abkündigung von Win XP-Support lässt alte IE-Browser verschwinden

• genauer müssen unterstütze Prokollversionen (ab wann) und Zielplattformen zusammen evaluiert werden

• Beispiel: Android-Browser erst ab Android 4.4, andere Browser für Android schon eher

• Beispiel: Web-Seite soll auch zur App auf Handys werden, ein Ansatz mit Apache Cordova / Phonegap, unterstützt nur etwas ältere WebSocket-Version

Komponentenbasierte Software-Entwicklung

Page 182: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

730

Verbreitung (2/2)

aktueller Stand: http://caniuse.com/websockets

• IE ab 10.0, Edge ab Start

• Firefox ab 11.0

• Chrome ab 16

• Safari ab 7.0

• Opera ab 12.1

• iOS Safari ab 6.1

• Android Browser ab 4.4

• Blackberry Browser ab 7.0

• Chrome for Android ab 33.0

• Firefox for Android ab 26

• IE Mobile ab 10.0

Komponentenbasierte Software-Entwicklung

Page 183: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

731

grobe Funktionsweise / Potenzial

• Client und Server in Java möglich, genauso gut können aber Clients in anderen Sprachen geschrieben werden (Server auch)

• Verbindung mit Server wird über HTTP hergestellt, Server dabei auf Upgrade auf WebSocket-Protokoll befragt

typische Adresse: new URI("ws://localhost:1790/hallo/echo")

• wenn Server Upgrade anbietet, wird bidirektional nutzbare Verbindung aufgebaut (ohne dass diese physikalisch gehalten werden muss)

• wenn Server kein Upgrade anbietet, ist Ansatz gescheitert

• es gibt verschiedene Protokoll-Versionen, auch hier muss sich auf eine geeinigt werden

Komponentenbasierte Software-Entwicklung

Page 184: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

732

etwas Hintergrund

• Auf TCP basierendes Netzwerkprotokoll

• Bidirektionale – Vollduplex Kommunikation

• Verbindung basiert auf einem einzigen Socket

• Datenübertragung mit geringer Latenzzeit

• Datenaustausch: binär, utf-8, …, nur Zeichenketten oder Byte-Buffer

• Websocket-Verbindung: ws:// und wss://

• keine Probleme bei Firewalls und Proxy-Servern

• Referenzimplementierung: Tyrus https://tyrus.java.net/

• Alternativen: GNU WebSocket4J, Webbit, Tootallnate

Komponentenbasierte Software-Entwicklung

Page 185: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

733

zentrale Nachrichten

Server Client

onOpen Verbindungsaufbau onOpen

onMessage senden und empfangen onMessage

onClose Verbindungsabbau onClose

onError Fehlerfall onError

eigentliches Protokoll, was in welcher Form ausgetauscht wird, muss von Entwicklern festgelegt werden

Begriff „Socket“ kann ernst genommen werden

Komponentenbasierte Software-Entwicklung

Page 186: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

734

Erstes Beispiel (1/7): Gewünscht

Client Server

connectToServer

@OnOpen (Bestätigung)

send(Hello) @OnMessage

@OnMessage send(Hallo Client)

send(Hello again) @OnMessage

@OnMessage send(Hallo Client)

(schließen) @OnClose

@OnClose (Bestätigung)

Komponentenbasierte Software-Entwicklung

Page 187: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

735

Erstes Beispiel (2/7): Server (1/2)

@ServerEndpoint("/echo")

public class EchoServer {

@OnOpen

public void onOpen(Session session, EndpointConfig cfg) {

System.out.println("@Server Anfrage URI: "

+ session.getRequestURI());

}

@OnMessage

public void onMessage(String message, Session session)

throws IOException {

System.out.println("@Server Nachricht: " + message);

session.getBasicRemote().sendText("Hallo Client");

}

Komponentenbasierte Software-Entwicklung

Page 188: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

736

Erstes Beispiel (3/7): Server (2/2)

@OnClose

public void onClose(Session session

, CloseReason closeReason) {

System.out.println("@Server CloseReason: "

+ closeReason);

}

@OnError

public void onError(Session session, Throwable thr) {

System.out.println("@Server Error: " + thr);

}

}

Komponentenbasierte Software-Entwicklung

Page 189: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

737

Erstes Beispiel (4/7): Client (1/3)

@ClientEndpoint

public class EchoClient {

@OnOpen

public void onOpen(Session session, EndpointConfig config) {

System.out.println("Id: " + session.getId()

+ "\nnegotiated: " + session.getNegotiatedSubprotocol()

+ "\nProtocol Version: " + session.getProtocolVersion()

+ "\nQuery String: " + session.getQueryString()

+ "\nRequestURI: " + session.getRequestURI()

+ "\nMaxIdleTimeout:" + session.getMaxIdleTimeout());

}

Komponentenbasierte Software-Entwicklung

Page 190: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

738

Erstes Beispiel (5/7): Client (2/3)

@OnMessage

public void onMessage(String message, Session session)

throws IOException {

System.out.println("@Client empfangen: " + message);

}

@OnClose

public void onClose(Session session, CloseReason closeReason) {

System.out.println("@Client CloseCode: "

+ closeReason.getCloseCode() + "\n@Client ReasonPhrase:"

+ closeReason.getReasonPhrase());

}

@OnError

public void onError(Session session, Throwable thr) {

System.out.println("@Client Error: " + thr);

}Komponentenbasierte Software-

Entwicklung

Page 191: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

739

Erstes Beispiel (6/7): Client (3/3)

public static void main(String[] args) {

WebSocketContainer container = ContainerProvider

.getWebSocketContainer();

try (Session session = container

.connectToServer(EchoClient.class, URI.create(

"ws://localhost:8080/WebSocketHelloWorld/echo"))) {

session.getBasicRemote().sendText("Hello");

session.getBasicRemote().sendText("Hello again");

System.out.println("1: " + session.isOpen());

session.close(new CloseReason( CloseCodes.NORMAL_CLOSURE

, "Schicht"));

System.out.println("2: " + session.isOpen());

} catch (Exception e) {

e.printStackTrace();

}

}

Komponentenbasierte Software-Entwicklung

Page 192: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

740

Erstes Beispiel (7/7): Ausgabe

Id: 2d80aea7-3d60-4a59-aaeb-56844cbbc25e

negotiated:

Protocol Version: 13

Query String: null

RequestURI: ws://localhost:8080/vlWebSocketEcho/echo

MaxIdleTimeout:0

1: true

@Client CloseCode: NORMAL_CLOSURE

@Client ReasonPhrase:Schicht

2: false

@Client empfangen: Hallo Client

INFO: @Server Anfrage URI: /vlWebSocketEcho/echo

INFO: @Server Nachricht: Hello

INFO: @Server Nachricht: Hello again

INFO: @Server CloseReason: CloseReason[1000,Schicht]

Komponentenbasierte Software-Entwicklung

Page 193: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

741

Analyse des ersten Beispiels

• Client und Server unterscheiden sich im Wesentlichen nur durch Annotationen @ClientEndpoint und @ServerEndpoint

• in JEE-Container führt @ServerEndpoint automatisch zum Deployen (läuft)

• beide nutzen @OnOpen, @OnMessage, @OnClose und gegebenenfalls @OnError

• zeigt Symmetrie der Kommunikationspartner

• wichtige (zu verwaltende) Objekte vom Typ Session

• Beispiel zeigt, dass es vom Timing abhängt, ob Bestätigung der zweiten Nachricht noch ankommt!

• keine explizite Nutzung von Threads notwendig; da paralleler Zugriff aber Synchronisation eventuell wichtig

Komponentenbasierte Software-Entwicklung

Page 194: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

742

2. Fallstudie (1/7): Realisierung eines Chats

• Clients können sich beim Server zum Chatten anmelden

• jede geschickte Nachricht wird an alle anderen verteilt

• Abmelden mit Nachricht „bye“ möglich

• (da wieder nur textbasiert, Überlappungen in Ein- und Ausgabe möglich)

• Server verwaltet Client-Sessions in einer synchronisierten Collection

Komponentenbasierte Software-Entwicklung

Page 195: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

743

2. Fallstudie (2/7): Server 1/2

@ServerEndpoint("/chat")

public class ChatServer {

private static Set<Session> partner =

Collections.synchronizedSet(new HashSet<Session>());

@OnOpen

public void onOpen(Session session, EndpointConfig config) {

this.partner.add(session);

}

@OnMessage

public void onMessage(String msg, Session s) throws IOException {

sende(msg);

}

@OnClose

public void onClose(Session session, CloseReason closeReason) {

this.partner.remove(session);

}

Komponentenbasierte Software-Entwicklung

Page 196: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

744

2. Fallstudie (3/7): Server 2/2

private void sende(String nachricht) {

try {

// nebenbei aufraeumen

List<Session> geschlossen = new ArrayList<>();

for (Session s : this.partner) {

if (!s.isOpen()) {

System.err.println("Geschlossen: " + s.getId());

geschlossen.add(s);

} else {

s.getBasicRemote().sendText(nachricht);

}

}

this.partner.removeAll(geschlossen);

System.out.println("Sende " + nachricht + " an "

+ this.partner.size() + " Klienten");

} catch (Throwable e) {

e.printStackTrace();

}

}

Komponentenbasierte Software-Entwicklung

Page 197: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

745

2. Fallstudie (4/7): Client 1/2

@ClientEndpoint

public class ChatClient {

@OnOpen

public void onOpen(Session session, EndpointConfig cfg) {

System.out.println("verbunden");

}

@OnMessage

public void onMessage(String msg, Session s) throws IOException {

System.out.println("@Client empfangen: " + msg);

}

@OnClose

public void onClose(Session session, CloseReason closeReason) {

System.out.println("abgemeldet");

}

Komponentenbasierte Software-Entwicklung

Page 198: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

746

2. Fallstudie (5/7): Client 2/2

public static void main(String[] args) {

WebSocketContainer container = ContainerProvider

.getWebSocketContainer();

try (Session session = container.connectToServer(ChatClient.class

, URI.create("ws://localhost:8080/WebSocketChat/chat"))) {

String eingabe= "";

while (!eingabe.toLowerCase().equals("bye")){

System.out.print("Beitrag: ");

eingabe = new Scanner(System.in).nextLine();

session.getBasicRemote().sendText(eingabe);

}

session.close(new CloseReason(CloseReason.CloseCodes

.NORMAL_CLOSURE, "Schicht"));

} catch (Exception e) {

e.printStackTrace();

}

}

} Komponentenbasierte Software-Entwicklung

Page 199: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

747

2. Fallstudie (6/7): Ausgabe (Eingaben markiert)

Beitrag: verbunden

Wer ist da

Beitrag: @Client

empfangen: Wer ist da

@Client empfangen:

ich

@Client empfangen:

ich auch

@Client empfangen:

bye

@Client empfangen:

bye

bye

@Client empfangen:

bye

abgemeldet

Beitrag: verbunden

@Client empfangen:

Wer ist da

ich

Beitrag: @Client

empfangen: ich

@Client empfangen:

ich auch

@Client empfangen:

bye

bye

@Client empfangen:

bye

abgemeldet

Beitrag: verbunden

@Client empfangen:

Wer ist da

@Client empfangen:

ich

ich auch

Beitrag: @Client

empfangen: ich auch

bye

@Client empfangen:

bye

abgemeldet

Komponentenbasierte Software-Entwicklung

Page 200: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

748

2. Fallstudie (7/7): Ausgabe Server

INFO: Sende Wer ist da an 3 Klienten

INFO: Sende ich an 3 Klienten

INFO: Sende ich auch an 3 Klienten

INFO: Sende bye an 3 Klienten

INFO: Sende bye an 2 Klienten

INFO: Sende bye an 1 Klienten

Komponentenbasierte Software-Entwicklung

Page 201: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

749

Ein- und Auspacken

• Zum Verschicken von Objekten werden sie in einfache Strings verwandelt

• hier bietet sich wieder JSON an

• für benötigte Klassen werden Encoder und Decoder geschrieben, die dem Client und Server bekannt gemacht werden

• folgendes Beispiel: Austausch von Sprint-Informationen mit JavaScript-Client (sehr elementar gehalten)

• Auch ByteStreams übertragbar

Komponentenbasierte Software-Entwicklung

Page 202: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

750

Sprint- Fallstudie (1/14): Sprints encoden 1/2

public class SprintsEncoder

implements Encoder.TextStream<List<Sprint>> {

@Override

public void encode(List<Sprint> sprints, Writer writer) {

JsonProvider provider = JsonProvider.provider();

JsonArrayBuilder elemente = Json.createArrayBuilder();

for (Sprint s : sprints) {

elemente.add(jsonSprint(s, false)); // von REST bekannt

}

JsonObject js = Json.createObjectBuilder()

.add("sprints", elemente).build();

try (JsonWriter jsonWriter =

provider.createWriter(writer)) {

jsonWriter.write(js);

}

}

was soll codiert werden

Komponentenbasierte Software-Entwicklung

Page 203: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

751

Sprint- Fallstudie (2/14): Sprints encoden 2/2

@Override

public void init(EndpointConfig config) {

}

@Override

public void destroy() {

}

//leider Copy & Paste

private JsonObject jsonSprint(Sprint s, boolean einzeln) {

...

}

Komponentenbasierte Software-Entwicklung

Page 204: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

752

Sprint- Fallstudie (3/14): Sprint decoden 1/2

public class SprintDecoder

implements Decoder.TextStream<Sprint> {

private SimpleDateFormat formatter

= new SimpleDateFormat("dd.MM.yyyy");

@Override

public Sprint decode(Reader reader){

JsonProvider provider = JsonProvider.provider();

JsonReader jsonReader = provider.createReader(reader);

JsonObject js = jsonReader.readObject();

Sprint sprint = new Sprint();

sprint.setMotto(js.getString("motto"));

try {

sprint.setStarttermin(formatter

.parse(js.getString("starttermin")));

was soll decodiert werden

Komponentenbasierte Software-Entwicklung

Page 205: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

753

Sprint- Fallstudie (4/14): Sprint decoden 2/2

sprint.setEndtermin(formatter

.parse(js.getString("endtermin")));

} catch (ParseException ex) {}

try {

sprint.setGeplanterAufwand(js.getInt("geplanterAufwand"));

} catch (Exception e){

sprint.setGeplanterAufwand(Integer

.parseInt(js.getString("geplanterAufwand")));

}

return sprint;

}

@Override public void init(EndpointConfig config) {}

@Override public void destroy() {}

}Komponentenbasierte Software-

Entwicklung

Page 206: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

754

Sprint- Fallstudie (5/14): SprintServer 1/3

@ServerEndpoint(value="/socketsprint"

, encoders={SprintsEncoder.class}

, decoders={SprintDecoder.class})

public class SprintServer implements Serializable{

@Inject

PersistenzService pers;

private static Set<Session> partner = Collections

.synchronizedSet(new HashSet<Session>());

@OnOpen

public void onOpen(Session session, EndpointConfig cfg) {

this.partner.add(session);

sende(); // besser nur an einen

}

Komponentenbasierte Software-Entwicklung

Page 207: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

755

Sprint- Fallstudie (6/14): SprintServer 2/3

@OnMessage

public void onMessage(Sprint sprint, Session session)

throws IOException {

try{

this.pers.persist(sprint);

sende();

} catch (Exception e){

// Benachrichtigung an den Client fehlt

}

}

@OnClose

public void onClose(Session session, CloseReason cR) {

this.partner.remove(session);

}

hier wird Decodierung genutzt

Komponentenbasierte Software-Entwicklung

Page 208: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

756

Sprint- Fallstudie (7/14): SprintServer 3/3

public void sende() {

try {

List<Session> geschlossen = new ArrayList<>();

List<Sprint> sprints = pers.findAllSprint();

for (Session s : this.partner) {

if (!s.isOpen()) {

System.err.println("Geschlossen: " + s.getId());

geschlossen.add(s);

} else {

s.getAsyncRemote().sendObject(sprints);

}

}

this.partner.removeAll(geschlossen);

} catch (Throwable e) {

e.printStackTrace();

}

}

}

Komponentenbasierte Software-Entwicklung

Page 209: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

757

Sprint- Fallstudie (8/14): JavaScript-Client 1/6

<!DOCTYPE html>

<html>

<head>

<title>WebSocket Client für Sprints</title>

<meta http-equiv="Content-Type"

content="text/html; charset=UTF-8">

<script type="text/javascript" src="js/ws.js"></script>

</head>

<body>

<form name="felder">

<div id="eingabe">

Motto : <input type="text" id="motto"><br>

Starttermin: <input type="text" id="starttermin"><br>

Endtermin: <input type="text" id="endtermin"><br>

geplanter Aufwand: <input type="text"

id="geplanterAufwand"><br>

</div>

Komponentenbasierte Software-Entwicklung

Page 210: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

758

Sprint- Fallstudie (9/14): JavaScript-Client 2/6

<div id="button">

<input type="button" value="absenden"

onClick="sende();"><br>

<input type="button" value="beenden" onClick="ws.close();">

</div>

<div id="sprints"

style="background-color: white; margin:5px;">

</div>

</form>

</body>

</html>

Komponentenbasierte Software-Entwicklung

Page 211: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

759

Sprint- Fallstudie (10/14): JavaScript-Client 3/6

// Zuerst ueberpruefen, ob der Browser Websocket unterstuetzt

// wird am Ende des Scripts gestartet

if ("WebSocket" in window) {

var ws = new

WebSocket("ws://localhost:8080/Sprinter/socketsprint");

//wird bei erfolgreichem Verbindungsaufbau aufgerufen

ws.onopen = function() {

//alert("open");

};

// wird aufgerufen, wenn Server Daten schickt

ws.onmessage = function(event) {

// geht ohne eval

var objJSON = eval("(function()

{return " + event.data + ";})()");

document.getElementById("sprints")

.innerHTML = table(objJSON.sprints);

};Komponentenbasierte Software-

Entwicklung

Page 212: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

760

Sprint- Fallstudie (11/14): JavaScript-Client 4/6

//wird aufgerufen, wenn Verbindung geschlossen wurde

ws.onclose = function() {

alert("Client beendet Verbindung");

};

// Fehlermeldung

ws.onerror = function(error) {

alert("Ein Fehler ist aufgetretten " + error);

};

} else {

alert("Dein Browser ist zu alt");

}

Komponentenbasierte Software-Entwicklung

Page 213: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

761

Sprint- Fallstudie (12/14): JavaScript-Client 5/6

function sende() {

var sprint = {

motto: document.getElementById("motto").value,

starttermin: document.getElementById('starttermin').value,

endtermin: document.getElementById('endtermin').value,

geplanterAufwand:

document.getElementById('geplanterAufwand').value

};

//mit stringify zum JSON Objekt kodieren und abschicken

ws.send('' + JSON.stringify(sprint));

//Eingabefelder leeren

document.getElementById('motto').value = '';

document.getElementById('starttermin').value = '';

document.getElementById('endtermin').value = '';

document.getElementById('geplanterAufwand').value = '';

} Komponentenbasierte Software-Entwicklung

Page 214: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

762

Sprint- Fallstudie (13/14): JavaScript-Client 6/6

function table(data) {

var erg = "<table border='1'>";

erg += "<tr><th>Id</th><th>Motto</th><th>Start</th>";

erg += "<th>Ende</th><th>Geplanter Aufwand</th></tr>";

for (var i = 0; i < data.length; i++) {

erg += "<tr style='background-color:" + data[i].farbe + "'>";

erg += "<td>" + data[i].id + "</td>";

erg += "<td>" + data[i].motto + "</td>";

erg += "<td>" + data[i].starttermin + "</td>";

erg += "<td>" + data[i].endtermin + "</td>";

erg += "<td>" + data[i].geplanterAufwand + "</td>";

erg += "</tr>";

}

erg += "</table>";

return erg;

}Komponentenbasierte Software-

Entwicklung

Page 215: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

763

Sprint- Fallstudie (14/14): Beispielnutzung

Komponentenbasierte Software-Entwicklung

Page 216: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

764

nächste Schritte

• Anmerkung: Die Seite ist so mit Code-Injection angreifbar

• HTML-Client bekommt nicht mit, wenn in JSF-Applikation Sprint bearbeitet wird

• verschiedene Schritte denkbar

– Methode sende() von SprintServer wird aufgerufen, wenn ein Sprint-Objekt bearbeitet wird (z. B. in Persistieren einbauen)

– Persistierung erzeugt Events, wenn Sprint-Objekte bearbeitet werden, SprintServer abonniert diese

• nächste Folie; nur kleine Änderungen im SprintControllervon JSF (Änderungen durch REST-Client werden so nicht erkannt)

Komponentenbasierte Software-Entwicklung

Page 217: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

765

Verknüpfung JSF mit WebSocket-Server

@Named

@SessionScoped

public class SprintController implements Serializable {

@Inject

SprintServer server;

...

public String uebernehmen() { // analog loeschen

...

server.sende();

...

Komponentenbasierte Software-Entwicklung

Page 218: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

766

weitere Überlegung

Löschen und Bearbeiten prinzipiell kein Problem:

• es wird aber ein erweitertes Protokoll benötigt

• z. B. erste Eigenschaft gibt an, was gemacht werden soll

• dann würde nicht Sprint-Klasse sondern Befehlsklasse zum Dekodieren im Server genutzt

Weiterführend

• Übertragung von Byte-Streams, z. B, zum Verschicken von Bildern

Komponentenbasierte Software-Entwicklung

Page 219: 6.11 Testen von Web-Applikationen - Seleniumhome.edvsz.fh-osnabrueck.de/skleuker/WS16_KbSE/WS16KbSE_Teil6.pdf · Prof. Dr. Stephan Kleuker 552 Selenium WebDriver - Konfiguration •unterstützt

Prof. Dr. Stephan Kleuker

767

Bedeutung von JavaScript

• Ursprünglich war JavaScript nur Hilfssprache, um kleine Berechnungen und Modifikationen im Browser zu ermöglichen

• mit HTML 5 wurde JavaScript zur zentralen Sprache des Internets

• Software-Engineering mit JavaScript steckt noch in den Kinderschuhen

• keine Klassenbibliothek, keine Standard-Frameworks

• eine unübersichtliche Menge sehr kreativer Lösungen

• Beispiel Varianten vom MV*-Pattern

• viele gute Werkzeuge und Hilfsmittel: JQuery, Jasmine, Istanbul, Karma, Selenium, …

Komponentenbasierte Software-Entwicklung