— Drohnen und WARP-Antriebe —
JSF-Anwendungen mit
Arquillian Drone und
Arquillian WARP testen
Bernd M¨uller, JAX 2014, 15.5.2014 2/61
Agenda
Arquillian
Arquillian Drone
Arquillian WARP
Bernd M¨uller, JAX 2014, 15.5.2014 3/61
Vorstellung Referent
Prof. Informatik (Ostfalia, HS Braunschweig/Wolfenb¨uttel)
Buchautor (JSF, Seam, JPA, ...)
Mitglied EGs JSR 344 (JSF 2.2) und JSR 338 (JPA 2.1)
Gesch¨aftsf¨uhrer PMST GmbH
. . .
Bernd M¨uller, JAX 2014, 15.5.2014 4/61
Arquillian
Bernd M¨uller, JAX 2014, 15.5.2014 5/61
Arquillian in der Selbstdarstellung
Auszug aus http://www.arquillian.org/
So you can rule your code. Not the bugs.
No more mocks.
No more container lifecycle and deployment hassles.
Just real tests!
Bernd M¨uller, JAX 2014, 15.5.2014 6/61
Kurzbeschreibung Arquillian
JBoss’ Test-Framework f¨ur Tests im Container
Dazu JUnit oder TestNG als Test-Runner
Und Test-Enricher, um Tests im Container laufen zu lassen
Und ShrinkWrap als Werkzeug f¨urs Packaging/Deployment
Prinzipieller Ablauf:
Test wird auf Client gepackt
Test und Laufzeiterweiterung wird im Container deployt
Test wird ausgef¨uhrt
Testergebnisse werden an Client zur¨uckgegeben
Test wird undeployt
Aktuell: Arquillian Core Version 1.1.4.Final, 31.3.2014
Bernd M¨uller, JAX 2014, 15.5.2014 7/61
Kurzbeschreibung Arquillian
JBoss’ Test-Framework f¨ur Tests im Container
Dazu JUnit oder TestNG als Test-Runner
Und Test-Enricher, um Tests im Container laufen zu lassen
Und ShrinkWrap als Werkzeug f¨urs Packaging/Deployment
Prinzipieller Ablauf:
Test wird auf Client gepackt
Test und Laufzeiterweiterung wird im Container deployt
Test wird ausgef¨uhrt
Testergebnisse werden an Client zur¨uckgegeben
Test wird undeployt
Aktuell: Arquillian Core Version 1.1.4.Final, 31.3.2014
Bernd M¨uller, JAX 2014, 15.5.2014 7/61
Kurzbeschreibung Arquillian
JBoss’ Test-Framework f¨ur Tests im Container
Dazu JUnit oder TestNG als Test-Runner
Und Test-Enricher, um Tests im Container laufen zu lassen
Und ShrinkWrap als Werkzeug f¨urs Packaging/Deployment
Prinzipieller Ablauf:
Test wird auf Client gepackt
Test und Laufzeiterweiterung wird im Container deployt
Test wird ausgef¨uhrt
Testergebnisse werden an Client zur¨uckgegeben
Test wird undeployt
Aktuell: Arquillian Core Version 1.1.4.Final, 31.3.2014
Bernd M¨uller, JAX 2014, 15.5.2014 7/61
Container, Deployments, Protokolle, Adapter
3 Betriebsmodi
Embedded Container
Managed Container
Remote Container
Protokolle
Local (embedded)
Servlet 2.5 / 3.0
JMX (nur JBoss)
Container-Adapter
JBoss-AS 4,5,6,7,8
Tomcat, Jetty
GlassFish
WebLogic
WebSphere
Im Zweifel: googeln und ausprobieren
Bernd M¨uller, JAX 2014, 15.5.2014 8/61
Container, Deployments, Protokolle, Adapter
3 Betriebsmodi
Embedded Container
Managed Container
Remote Container
Protokolle
Local (embedded)
Servlet 2.5 / 3.0
JMX (nur JBoss)
Container-Adapter
JBoss-AS 4,5,6,7,8
Tomcat, Jetty
GlassFish
WebLogic
WebSphere
Im Zweifel: googeln und ausprobieren
Bernd M¨uller, JAX 2014, 15.5.2014 8/61
Container, Deployments, Protokolle, Adapter
3 Betriebsmodi
Embedded Container
Managed Container
Remote Container
Protokolle
Local (embedded)
Servlet 2.5 / 3.0
JMX (nur JBoss)
Container-Adapter
JBoss-AS 4,5,6,7,8
Tomcat, Jetty
GlassFish
WebLogic
WebSphere
Im Zweifel: googeln und ausprobieren
Bernd M¨uller, JAX 2014, 15.5.2014 8/61
Beispiel: Test-Runner und Deployment
@RunWith(Arquillian.class)
public class CustomerServiceTest {
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class , "test.war")
.addClasses(Customer.class , CustomerService .class)
.addAsResource("META -INF/persistence.xml")
. addAsWebInfResource (
new File("src/main/webapp/WEB -INF/beans.xml"));
}
...
Bernd M¨uller, JAX 2014, 15.5.2014 9/61
Beispiel: Test-Runner und Deployment
@RunWith(Arquillian.class)
public class CustomerServiceTest {
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class , "test.war")
.addClasses(Customer.class , CustomerService .class)
.addAsResource("META -INF/persistence.xml")
. addAsWebInfResource (
new File("src/main/webapp/WEB -INF/beans.xml"));
}
...
Bernd M¨uller, JAX 2014, 15.5.2014 9/61
ShrinkWrap
Werkzeug zur Erstellung/Manipulation von Java-Archiven
(JARs, WARs, EARs)
Fr¨uher eigenst¨andiges JBoss-Projekt, jetzt
Arquillian-Teilprojekt
Fluent-API zum Erstellen eines Archives,
f¨ur sogenannte Micro Deployment,
im Beispiel zwei Klassen und Deployment-Descriptoren
Bernd M¨uller, JAX 2014, 15.5.2014 10/61
Verbesserungspotenzial
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class ,
generatedName)
.addPackage(true , Customer.class.getPackage ())
.addAsResource("META -INF/test -persistence.xml",
"META -INF/persistence.xml")
. addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml");
}
Generierter Deployment-Name
Ganzes Package, optional mit Sub-Packages
Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . )
Leerer Deployment-Descriptor, auch String-Asset
Bernd M¨uller, JAX 2014, 15.5.2014 11/61
Verbesserungspotenzial
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class ,
generatedName)
.addPackage(true , Customer.class.getPackage ())
.addAsResource("META -INF/test -persistence.xml",
"META -INF/persistence.xml")
. addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml");
}
Generierter Deployment-Name
Ganzes Package, optional mit Sub-Packages
Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . )
Leerer Deployment-Descriptor, auch String-Asset
Bernd M¨uller, JAX 2014, 15.5.2014 11/61
Verbesserungspotenzial
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class ,
generatedName)
.addPackage(true , Customer.class.getPackage ())
.addAsResource("META -INF/test -persistence.xml",
"META -INF/persistence.xml")
. addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml");
}
Generierter Deployment-Name
Ganzes Package, optional mit Sub-Packages
Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . )
Leerer Deployment-Descriptor, auch String-Asset
Bernd M¨uller, JAX 2014, 15.5.2014 11/61
Verbesserungspotenzial
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class ,
generatedName)
.addPackage(true , Customer.class.getPackage ())
.addAsResource("META -INF/test -persistence.xml",
"META -INF/persistence.xml")
. addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml");
}
Generierter Deployment-Name
Ganzes Package, optional mit Sub-Packages
Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . )
Leerer Deployment-Descriptor, auch String-Asset
Bernd M¨uller, JAX 2014, 15.5.2014 11/61
Verbesserungspotenzial
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class ,
generatedName)
.addPackage(true , Customer.class.getPackage ())
.addAsResource("META -INF/test -persistence.xml",
"META -INF/persistence.xml")
. addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml");
}
Generierter Deployment-Name
Ganzes Package, optional mit Sub-Packages
Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . )
Leerer Deployment-Descriptor, auch String-Asset
Bernd M¨uller, JAX 2014, 15.5.2014 11/61
Beispiel: Zu testende EJB
@Stateless
public class CustomerService {
@PersistenceContext
EntityManager em;
public void persist(Customer customer) {
em.persist(customer );
}
public long getNumberOfCustomers () {
return em. createNamedQuery (
"Customer. getNumberOfCustomers ",
Long.class ). getSingleResult ();
}
}
Bernd M¨uller, JAX 2014, 15.5.2014 12/61
Beispiel: Der Test
@RunWith(Arquillian.class)
public class CustomerServiceTest {
@Deployment
public static Archive <?> createTestArchive () { ...}
@Inject
CustomerService customerService ;
@Test
public void testPersist () {
Customer customer = new Customer("Firstname", "Lastname"
assertNull(customer.getId ()); // ueberfluessig
customerService .persist(customer );
assertNotNull(customer.getId ());
}
Bernd M¨uller, JAX 2014, 15.5.2014 13/61
Beispiel: Alternativer Test
@Test
public void testPersist2 () {
Customer customer = new Customer("Firstname", "Lastname"
Long before = customerService . getNumberOfCustomers ();
customerService .persist(customer );
Long after= customerService . getNumberOfCustomers ();
assertTrue("Muss ein Customer mehr sein",
before + 1 == after );
}
Bernd M¨uller, JAX 2014, 15.5.2014 14/61
Beispiel: 3. Alternative mit Persistenzkontext
@RunWith(Arquillian.class)
public class CustomerServiceTest {
@PersistenceContext
EntityManager em;
@Test
public void testPersist3 () {
Customer customer = new Customer("Firstname", "Lastname"
Long before = em. createNamedQuery (
"Customer. getNumberOfCustomers ", Long.class)
. getSingleResult ();
customerService .persist(customer );
Long after= em. createNamedQuery (
"Customer. getNumberOfCustomers ", Long.class)
. getSingleResult ();
assertTrue("Muss ein Customer mehr sein",
before + 1 == after );
}
Beispiel: 3. Alternative mit Persistenzkontext
@RunWith(Arquillian.class)
public class CustomerServiceTest {
@PersistenceContext
EntityManager em;
@Test
public void testPersist3 () {
Customer customer = new Customer("Firstname", "Lastname"
Long before = em. createNamedQuery (
"Customer. getNumberOfCustomers ", Long.class)
. getSingleResult ();
customerService .persist(customer );
Long after= em. createNamedQuery (
"Customer. getNumberOfCustomers ", Long.class)
. getSingleResult ();
assertTrue("Muss ein Customer mehr sein",
before + 1 == after );
}
Existiert, da Test in Container
”
Richtige Anwendungen“: Multiple Deployments (Doku)
@Deployment(name = "dep1", order = 1)
public static WebArchive createDep1 () { ... }
@Deployment(name = "dep2", order = 2)
public static WebArchive createDep2 () { ... }
@Test @OperateOnDeployment ("dep1")
public void testRunningInDep1 () { ... }
@Test @OperateOnDeployment ("dep2")
public void testRunningInDep2 () { ... }
Bernd M¨uller, JAX 2014, 15.5.2014 16/61
Erweiterbarkeit
Wie alle modernen Systeme/Frameworks besitzt Arquillian ein
Service Provider Interface
Aktuelle Erweiterungen:
Drone (Web-UI)
WARP (JSF)
Persistence
Performance
Graphene (UI, AJAX)
Seam 2
Bernd M¨uller, JAX 2014, 15.5.2014 17/61
Arquillian Drone
Bernd M¨uller, JAX 2014, 15.5.2014 18/61
Arquillian Drone
Arquillian-Erweiterung f¨ur funktionale Tests
Basiert auf Selenium
Selenium-Slogan: Selenium automates browsers
WebDriver: M¨oglichkeit zur Browser-Steuerung, u.a. mit Java
API
WebDriver API das einzig neu zu lernende
¨Anderung des prinzipiellen Ablaufs: Tests auf Client
Kombination Client und Server m¨oglich
Version aktuell: 1.3.0.Final
Version 2.0.0.Alpha1 mit ¨uberarbeitetem/entschlacktem API
in Entwicklung (von uns nicht verwendet)
Bernd M¨uller, JAX 2014, 15.5.2014 19/61
Die n¨otigen Erweiterungen/¨Anderungen
@RunWith(Arquillian.class)
public class DroneUsedTest {
@ArquillianResource
URL deploymentURL;
@Drone
WebDriver driver;
@Deployment(testable = false)
public static Archive <?> createTestArchive () { ...}
@ArquillianResource: das URL des Deployments
@Drone: das WebDriver oder DefaultSelenium API
Keine Tests im Server
Bernd M¨uller, JAX 2014, 15.5.2014 20/61
Die n¨otigen Erweiterungen/¨Anderungen
@RunWith(Arquillian.class)
public class DroneUsedTest {
@ArquillianResource
URL deploymentURL;
@Drone
WebDriver driver;
@Deployment(testable = false)
public static Archive <?> createTestArchive () { ...}
@ArquillianResource: das URL des Deployments
@Drone: das WebDriver oder DefaultSelenium API
Keine Tests im Server
Bernd M¨uller, JAX 2014, 15.5.2014 20/61
Die n¨otigen Erweiterungen/¨Anderungen
@RunWith(Arquillian.class)
public class DroneUsedTest {
@ArquillianResource
URL deploymentURL;
@Drone
WebDriver driver;
@Deployment(testable = false)
public static Archive <?> createTestArchive () { ...}
@ArquillianResource: das URL des Deployments
@Drone: das WebDriver oder DefaultSelenium API
Keine Tests im Server
Bernd M¨uller, JAX 2014, 15.5.2014 20/61
Die n¨otigen Erweiterungen/¨Anderungen
@RunWith(Arquillian.class)
public class DroneUsedTest {
@ArquillianResource
URL deploymentURL;
@Drone
WebDriver driver;
@Deployment(testable = false)
public static Archive <?> createTestArchive () { ...}
@ArquillianResource: das URL des Deployments
@Drone: das WebDriver oder DefaultSelenium API
Keine Tests im Server
Bernd M¨uller, JAX 2014, 15.5.2014 20/61
Falls nicht nur Client-Tests
@RunWith(Arquillian.class)
public class DroneUsedTest {
@Drone
WebDriver driver;
@Deployment
public static Archive <?> createTestArchive () { ... }
@Test
@RunAsClient
@InSequence (1)
public void createCustomer( @ArquillianResource URL url) {
@Test // im Server
@InSequence (2)
public void countCustomers () { ... }
Auch Tests im Server m¨oglich, daher Unterscheidung
Reihenfolge der Tests (Widerspruch zur reinen Lehre?)
Falls nicht nur Client-Tests
@RunWith(Arquillian.class)
public class DroneUsedTest {
@Drone
WebDriver driver;
@Deployment
public static Archive <?> createTestArchive () { ... }
@Test
@RunAsClient
@InSequence (1)
public void createCustomer( @ArquillianResource URL url) {
@Test // im Server
@InSequence (2)
public void countCustomers () { ... }
Auch Tests im Server m¨oglich, daher Unterscheidung
Reihenfolge der Tests (Widerspruch zur reinen Lehre?)
Falls nicht nur Client-Tests
@RunWith(Arquillian.class)
public class DroneUsedTest {
@Drone
WebDriver driver;
@Deployment
public static Archive <?> createTestArchive () { ... }
@Test
@RunAsClient
@InSequence (1)
public void createCustomer( @ArquillianResource URL url) {
@Test // im Server
@InSequence (2)
public void countCustomers () { ... }
Auch Tests im Server m¨oglich, daher Unterscheidung
Reihenfolge der Tests (Widerspruch zur reinen Lehre?)
Versteht Arquillian Maven’s POM ?
Nein, aber ShrinkWrap
Es gibt einen ShrinkWrap-Resolver, der Maven und Gradle
unterst¨utzt
Jetzt Beispiel:
JSF-Seite zur Kundenneuanlage
Navigation zu Kundenanlage-Erfolgreich-Seite, falls kein Fehler
Test, ob Navigation funktioniert
Test, ob Daten im Server
Bernd M¨uller, JAX 2014, 15.5.2014 22/61
Versteht Arquillian Maven’s POM ?
Nein, aber ShrinkWrap
Es gibt einen ShrinkWrap-Resolver, der Maven und Gradle
unterst¨utzt
Jetzt Beispiel:
JSF-Seite zur Kundenneuanlage
Navigation zu Kundenanlage-Erfolgreich-Seite, falls kein Fehler
Test, ob Navigation funktioniert
Test, ob Daten im Server
Bernd M¨uller, JAX 2014, 15.5.2014 22/61
Das (fast) komplette Beispiel (Teil 1)
@RunWith(Arquillian.class)
public class CreateCustomerTest {
private static final String
WEBAPP_SRC = "src/main/webapp";
@Drone
WebDriver driver;
@Inject
CustomerRepository customerRepository ;
Bernd M¨uller, JAX 2014, 15.5.2014 23/61
Das (fast) komplette Beispiel (Teil 2)
@Deployment
public static Archive <?> createTestArchive () {
MavenDependencyResolver resolver =
DependencyResolvers .use( MavenDependencyResolver .class)
. loadMetadataFromPom ("pom.xml");
return ShrinkWrap.create(WebArchive.class , "test.war")
.addPackages (...). addClasses (...)
.addAsResource("META -INF/test -persistence.xml",
"META -INF/persistence.xml")
. addAsWebInfResource ("test -ds.xml")
. addAsWebResource (new File(WEBAPP_SRC ,
"create.xhtml"))
. addAsWebResource (new File(WEBAPP_SRC ,
"customer -created.xhtml"))
. addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml")
. addAsWebInfResource (
new StringAsset("<faces -config version ="2.0"/ >"),
"faces -config.xml")
.addAsLibraries (
resolver.artifact("org.seleniumhq.selenium:selenium -ja
. resolveAsFiles ());
}
Das (fast) komplette Beispiel (Teil 3)
@Test
@RunAsClient
@InSequence (1)
public void createCustomer( @ArquillianResource URL url) {
driver.get(url + "create.jsf");
driver.findElement(By.id("create:firstname"))
.sendKeys("firstname");
driver.findElement(By.id("create:lastname"))
.sendKeys("lastname");
driver.findElement(By.id("create:dob"))
.sendKeys("1.1.2000");
driver.findElement(By.id("create:email"))
.sendKeys("email");
driver.findElement(By.id("create:password"))
.sendKeys("password");
driver.findElement(By.id("create:create")). click ();
assertTrue(driver.findElement(
By.xpath("// body[contains(text(), ’Kunde angelegt ’)]"))
.isDisplayed ());
}
Das (fast) komplette Beispiel (Teil 4)
@Test // im Server
@InSequence (2)
public void countCustomers () {
assertEquals (1, customerRepository .getCustomers (). size ());
}
Bernd M¨uller, JAX 2014, 15.5.2014 26/61
@Drone im Detail
Injection in Klasse
Class-Based Life-Cycle
Analog zu @BeforeClass / @AfterClass
Injection in Methode
Method-based Life-Cycle
Analog zu @Before / @After
Mehrere Injektionen ¨uber Qualifier m¨oglich
Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver,
InternetExplorerDriver, SafariDriver
Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in
Test-Asserts
Bernd M¨uller, JAX 2014, 15.5.2014 27/61
@Drone im Detail
Injection in Klasse
Class-Based Life-Cycle
Analog zu @BeforeClass / @AfterClass
Injection in Methode
Method-based Life-Cycle
Analog zu @Before / @After
Mehrere Injektionen ¨uber Qualifier m¨oglich
Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver,
InternetExplorerDriver, SafariDriver
Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in
Test-Asserts
Bernd M¨uller, JAX 2014, 15.5.2014 27/61
@Drone im Detail
Injection in Klasse
Class-Based Life-Cycle
Analog zu @BeforeClass / @AfterClass
Injection in Methode
Method-based Life-Cycle
Analog zu @Before / @After
Mehrere Injektionen ¨uber Qualifier m¨oglich
Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver,
InternetExplorerDriver, SafariDriver
Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in
Test-Asserts
Bernd M¨uller, JAX 2014, 15.5.2014 27/61
@Drone im Detail
Injection in Klasse
Class-Based Life-Cycle
Analog zu @BeforeClass / @AfterClass
Injection in Methode
Method-based Life-Cycle
Analog zu @Before / @After
Mehrere Injektionen ¨uber Qualifier m¨oglich
Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver,
InternetExplorerDriver, SafariDriver
Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in
Test-Asserts
Bernd M¨uller, JAX 2014, 15.5.2014 27/61
@Drone im Detail
Injection in Klasse
Class-Based Life-Cycle
Analog zu @BeforeClass / @AfterClass
Injection in Methode
Method-based Life-Cycle
Analog zu @Before / @After
Mehrere Injektionen ¨uber Qualifier m¨oglich
Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver,
InternetExplorerDriver, SafariDriver
Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in
Test-Asserts
Bernd M¨uller, JAX 2014, 15.5.2014 27/61
Arquillian WARP
Bernd M¨uller, JAX 2014, 15.5.2014 28/61
Arquillian Warp
Client-seitige Tests mit Zusicherungen/Pr¨ufung von
Server-seitiger Logik und Zustand
Keine weiteren Bibliotheken, wie etwa Selenium, ben¨otigt
Kein UI ben¨otigt (Headless)
Speziell f¨ur Servlets und Servlet-basierte Systeme gemacht
Im Augenblick nur Servlets direkt und JSF 2 unterst¨utzt
Arquillian Spring Framework Extension enth¨alt Warp Spring
MVC Extension (nicht betrachtet)
Offizieller Nachfolger von JSFUnit
Aktuell: Version 1.0.0.Alpha7, 11.3.2014
Bernd M¨uller, JAX 2014, 15.5.2014 29/61
Die prinzipielle Idee hinter WARP
Initiierung eines HTTP-Requests auf Client-Seite z.B. mit
WebDriver
Im selben Request-Zyklus Ausf¨uhren von Server-seitigen Tests
im Container
Dazu:
Initiieren des Request ¨uber Interface Activity
Inspizieren des Server-Zustands ¨uber Klasse Inspection
Aktivity mit perform()-Methode
Inspection mit JUnit/TestNG-Tests zum
”
richtigen“ Zeitpunkt
optional: Gruppieren und Observieren von Requests
Bernd M¨uller, JAX 2014, 15.5.2014 30/61
Die n¨otigen Erweiterungen/¨Anderungen
@WarpTest f¨ur Test-Klasse
@RunAsClient f¨ur Test-Klasse
@BeforeServlet, @AfterServlet f¨ur Servlet-Tests
@BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests
Im Folgenden 3 Beispiele
Existieren die richtigen Beans?
Validierung
Navigation
Bernd M¨uller, JAX 2014, 15.5.2014 31/61
Die n¨otigen Erweiterungen/¨Anderungen
@WarpTest f¨ur Test-Klasse
@RunAsClient f¨ur Test-Klasse
@BeforeServlet, @AfterServlet f¨ur Servlet-Tests
@BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests
Im Folgenden 3 Beispiele
Existieren die richtigen Beans?
Validierung
Navigation
Bernd M¨uller, JAX 2014, 15.5.2014 31/61
Die n¨otigen Erweiterungen/¨Anderungen
@WarpTest f¨ur Test-Klasse
@RunAsClient f¨ur Test-Klasse
@BeforeServlet, @AfterServlet f¨ur Servlet-Tests
@BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests
Im Folgenden 3 Beispiele
Existieren die richtigen Beans?
Validierung
Navigation
Bernd M¨uller, JAX 2014, 15.5.2014 31/61
Die n¨otigen Erweiterungen/¨Anderungen
@WarpTest f¨ur Test-Klasse
@RunAsClient f¨ur Test-Klasse
@BeforeServlet, @AfterServlet f¨ur Servlet-Tests
@BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests
Im Folgenden 3 Beispiele
Existieren die richtigen Beans?
Validierung
Navigation
Bernd M¨uller, JAX 2014, 15.5.2014 31/61
1. Beispiel: Existieren die richtigen Beans?
Weld-Manual: Einloggen ¨uber JSF-View-Bean
Pr¨ufen auf Benutzername/Passwort ¨uber EJB
CDI-produzierte Customer-Instanz im Session-Scope
Die Existenz dieser Instanz soll ¨uberpr¨uft werden
Bernd M¨uller, JAX 2014, 15.5.2014 32/61
JSF Login-Bean
@Named
@SessionScoped
public class Login implements Serializable {
@Inject
Credentials credentials;
@Inject
CustomerService customerService ;
private Customer loggedInCustomer ;
...
Bernd M¨uller, JAX 2014, 15.5.2014 33/61
JSF Login-Bean (cont’d)
public void login () {
loggedInCustomer = customerService .getCustomer (...
if ( loggedInCustomer == null) {
FacesMessage message = new FacesMessage("Falsche ...");
FacesContext. getCurrentInstance (). addMessage (...);
}
}
@Produces @LoggedIn
Customer getloggedInCustomer () {
return loggedInCustomer ;
}
public void logout () {
loggedInCustomer = null;
}
Bernd M¨uller, JAX 2014, 15.5.2014 34/61
Logged-In-Test
@RunWith(Arquillian.class)
@WarpTest
@RunAsClient
public class LoggedInTest {
@Deployment
public static Archive <?> createTestArchive () {
// nichts besonderes
}
@ArquillianResource
URL contextPath;
@Drone
WebDriver browser;
Bernd M¨uller, JAX 2014, 15.5.2014 35/61
Logged-In-Test (cont’d)
@Test
public void testLoggedIn () {
browser.navigate ().to(contextPath + "login.jsf");
browser.findElement(By.id("form:email")). sendKeys(EMAIL );
browser.findElement(By.id("form:password")). sendKeys(PASSW
Warp
.initiate(new Activity () {
public void perform () {
browser.findElement(By.id("form:login")). click ();
}})
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
@Inject
@LoggedIn
Customer customer;
Bernd M¨uller, JAX 2014, 15.5.2014 36/61
Struktur zur Verdeutlichung
Warp
.initiate(new Activity () {
...
})
.inspect(new Inspection () {
...
})
Aktivit¨at auf dem Client initiieren
Inspektion auf dem Server ausf¨uhren
Bernd M¨uller, JAX 2014, 15.5.2014 37/61
Logged-In-Test (cont’d)
Warp
.initiate(new Activity () {...} )
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
@Inject
@LoggedIn
Customer customer;
@BeforePhase(Phase. INVOKE_APPLICATION )
public void noCustomerExists () {
Assert.assertNull(
"LoggedIn Customer darf nicht existieren",
customer );
}
...
Bernd M¨uller, JAX 2014, 15.5.2014 38/61
Logged-In-Test (cont’d)
@BeforePhase(Phase. INVOKE_APPLICATION )
public void noCustomerExists () {
Assert.assertNull(
"LoggedIn Customer darf nicht existieren",
customer );
}
@AfterPhase(Phase. INVOKE_APPLICATION )
public void loggedInCustomerExists () {
Assert.assertNotNull(
"LoggedIn Customer muss existieren",
customer );
Assert.assertEquals("Falsche E-Mail",
EMAIL , customer.getEmail ());
Assert.assertEquals("Falsches Passwort",
PASSWORD , customer.getPassword ());
}
Bernd M¨uller, JAX 2014, 15.5.2014 39/61
Logged-In-Test (cont’d)
@BeforePhase(Phase. INVOKE_APPLICATION )
public void noCustomerExists () {
Assert.assertNull(
"LoggedIn Customer darf nicht existieren",
customer );
}
@AfterPhase(Phase. INVOKE_APPLICATION )
public void loggedInCustomerExists () {
Assert.assertNotNull(
"LoggedIn Customer muss existieren",
customer );
Assert.assertEquals("Falsche E-Mail",
EMAIL , customer.getEmail ());
Assert.assertEquals("Falsches Passwort",
PASSWORD , customer.getPassword ());
}
Bernd M¨uller, JAX 2014, 15.5.2014 39/61
Logged-In-Test (cont’d)
@BeforePhase(Phase. INVOKE_APPLICATION )
public void noCustomerExists () {
Assert.assertNull(
"LoggedIn Customer darf nicht existieren",
customer );
}
@AfterPhase(Phase. INVOKE_APPLICATION )
public void loggedInCustomerExists () {
Assert.assertNotNull(
"LoggedIn Customer muss existieren",
customer );
Assert.assertEquals("Falsche E-Mail",
EMAIL , customer.getEmail ());
Assert.assertEquals("Falsches Passwort",
PASSWORD , customer.getPassword ());
}
Bernd M¨uller, JAX 2014, 15.5.2014 39/61
2. Beispiel: Validierung
Credentials werden falsch eingegeben (zu kurz)
JSF erzeugt in Phase 3 FacesMessage-Instanzen
Pr¨ufen vor und nach Phase 3, ob Messages existieren oder
nicht
Bernd M¨uller, JAX 2014, 15.5.2014 40/61
Klasse Credentials
@Named
@RequestScoped
public class Credentials {
@NotNull
@Size(min = 6, max = 30)
private String email;
@NotNull
@Size(min = 6, max = 20)
private String password;
...
Deutsche Fehlermeldung f¨ur @Size: ”muss zwischen 6 ...
Bernd M¨uller, JAX 2014, 15.5.2014 41/61
Validierungstest
@RunWith(Arquillian.class)
@WarpTest
@RunAsClient
public class LoggedInValidationFailedTest {
// nichts besonderes im Deployment
@ArquillianResource
URL contextPath;
@Drone
WebDriver browser;
...
Bernd M¨uller, JAX 2014, 15.5.2014 42/61
Validierungstest (cont’d)
@Test
public void testValidation () {
browser.navigate ().to(contextPath + "login.jsf");
browser.findElement(By.id("form:email")). sendKeys("short")
browser.findElement(By.id("form:password")). sendKeys("shor
Warp
.initiate(new Activity () {
public void perform () {
browser.findElement(By.id("form:login")). click ();
}})
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
...
Bernd M¨uller, JAX 2014, 15.5.2014 43/61
Validierungstest (cont’d)
Warp
.initiate(new Activity () {...} )
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
@ArquillianResource
FacesContext facesContext;
@BeforePhase(Phase. PROCESS_VALIDATIONS )
public void noFacesMessage () {
Assert.assertEquals("Anzahl Fehler muss 0 sein",
0, facesContext.getMessageList (). size ());
}
...
Bernd M¨uller, JAX 2014, 15.5.2014 44/61
Validierungstest (cont’d)
Warp
.initiate(new Activity () {...} )
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
@ArquillianResource
FacesContext facesContext;
@BeforePhase(Phase. PROCESS_VALIDATIONS )
public void noFacesMessage () {
Assert.assertEquals("Anzahl Fehler muss 0 sein",
0, facesContext.getMessageList (). size ());
}
...
FacesContext injizierbar!
Bernd M¨uller, JAX 2014, 15.5.2014 44/61
Validierungstest (cont’d)
.inspect(new Inspection () {
...
@ArquillianResource
FacesContext facesContext;
@AfterPhase(Phase. PROCESS_VALIDATIONS )
public void facesMessagesExist () {
List <FacesMessage > messages =
facesContext.getMessageList ();
Assert.assertTrue(
facesContext.getMessageList (). size () != 0);
for (FacesMessage facesMessage : messages) {
Assert.assertTrue("Falsche Fehlermeldung",
facesMessage.getSummary ()
.startsWith("muss zwischen 6"));
}
}
Bernd M¨uller, JAX 2014, 15.5.2014 45/61
3. Beispiel: Navigation mit Redirect
Einfache JSF-Seiten mit Navigation und Redirect
Noch nicht erw¨ahntes WARP-Feature: Gruppieren von
Inspektionen auf Server basierend auf Request-Folge
Pr¨ufen der View-Id nach Restore-View-Phase
Bernd M¨uller, JAX 2014, 15.5.2014 46/61
JSF-Seiten mit Navigation
redirect-source.xhtml
<h:form id="form">
Seite verwendet #{ redirectSourceBean .name} <br />
<h:commandButton id="redirect"
action=" redirect-target ? faces-redirect=true"
value="Redirect to ’redirect-target .jsf ’" />
</h:form >
redirect-target.xhtml
<h:form id="form">
Seite verwendet #{ redirectTargetBean .name} />
</h:form >
Bernd M¨uller, JAX 2014, 15.5.2014 47/61
@RunWith(Arquillian.class)
@WarpTest
@RunAsClient
public class RedirectTest {
@Deployment
public static Archive <?> createTestArchive () {
return ShrinkWrap.create(WebArchive.class ,
"redirect -test.war")
...
. addAsWebResource (new File(WEBAPP_SRC ,
"redirect -source.xhtml"))
. addAsWebResource (new File(WEBAPP_SRC ,
"redirect -target.xhtml"))
...
}
@ArquillianResource URL contextPath;
@Drone WebDriver browser;
...
Bernd M¨uller, JAX 2014, 15.5.2014 48/61
Navigationstest (cont’d)
@Test
public void testRedirect () {
browser.navigate ().to(contextPath + "redirect -source.jsf")
Warp
.initiate(new Activity () {
public void perform () {
browser.findElement(By.id("form:redirect")). click ();
}})
.group("redirect -source.jsf")
.observe(HttpFilters.request (). index (1))
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
@AfterPhase(Phase.RESTORE_VIEW)
...
Bernd M¨uller, JAX 2014, 15.5.2014 49/61
Struktur zur Verdeutlichung
Warp
.initiate(new Activity () { ... }})
.group("redirect -source.jsf") // nur Doku
.observe(HttpFilters.request (). index (1))
.inspect(new Inspection () { ... })
.group("redirect -target.jsf") // nur Doku
.observe(HttpFilters.request (). index (2))
.inspect(new Inspection () { ... })
.execute ();
Assert.assertTrue(browser.getCurrentUrl ()
.contains("redirect -target.jsf"));
Bernd M¨uller, JAX 2014, 15.5.2014 50/61
Navigationstest (cont’d)
.group("redirect -source.jsf")
.observe(HttpFilters.request (). index (1))
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
@AfterPhase(Phase.RESTORE_VIEW)
public void verifyPage( @ArquillianResource
FacesContext facesContext) {
Assert.assertEquals("/redirect -source.xhtml",
facesContext.getViewRoot (). getViewId ());
}
})
Bernd M¨uller, JAX 2014, 15.5.2014 51/61
Navigationstest (cont’d)
.group("redirect -target.jsf")
.observe(HttpFilters.request (). index (2))
.inspect(new Inspection () {
private static final long serialVersionUID = 1L;
@AfterPhase(Phase.RESTORE_VIEW)
public void verifyPage( @ArquillianResource
FacesContext facesContext) {
Assert.assertEquals("/redirect -target.xhtml",
facesContext.getViewRoot (). getViewId ());
}
})
.execute ();
Assert.assertTrue(browser.getCurrentUrl ()
.contains("redirect -target.jsf"));
Bernd M¨uller, JAX 2014, 15.5.2014 52/61
Auswahl des richtigen Request
Da mehrere Request getriggert werden k¨onnen, muss man den
richtigen (den, den man observieren will) ausw¨ahlen
Dazu das HttpRequestFilter-Interface
Damit spezifiziert man den zu verwendenden HttpRequest der
aktuellen Gruppe
Bernd M¨uller, JAX 2014, 15.5.2014 53/61
Aus
”
Dokumentation“
import static org.jboss.arquillian.warp
.client.filter.http.HttpFilters.request;
// will accept only requests for HTML
... group ()
.observe(request (). uri (). contains(".html"))
// will accept only REST requests for JSON
... group ()
.observe(request (). header ()
.containsValue("Accept", "application/json"))
// will accept only POST requests
... group ()
.observe(request (). method (). equal(POST ))
Bernd M¨uller, JAX 2014, 15.5.2014 54/61
Was kann alles injiziert werden?
Injizierbar ¨uber @ArquillianResource
Servlet-Ressourcen
ServletRequest or HttpServletRequest
ServletResponse or HttpServletResponse
Bernd M¨uller, JAX 2014, 15.5.2014 55/61
Was kann alles injiziert werden? (cont’d)
Injizierbar ¨uber @ArquillianResource
JSF-Ressourcen
FacesContext
Application
ELContext, ELResolver, ExpressionFactory
ExceptionHandler
Flash
NavigationHandler
PartialViewContext
RenderKit
ResourceHandler
StateManager
UIViewRoot
ViewHandler
Bernd M¨uller, JAX 2014, 15.5.2014 56/61
Wo Licht ist, ist auch Schatten
Sehr schlechte Doku
Noch viele/schwere Fehler
Scheinbar Ein-Mann-Projekt: Luk´aˇs Fryˇc (Project Lead)
Bernd M¨uller, JAX 2014, 15.5.2014 57/61
Dokumentation WARP
Bernd M¨uller, JAX 2014, 15.5.2014 58/61
Zusammenfassung und (pers¨onliches) Fazit
Einerseits . . .
EAP Dokumentation enth¨alt kein Kapitel zu Arquillian
JBoss Dokumentation enh¨alt kein Kapitel zu WARP
Andererseits . . .
EAP Quickstarts enthalten Arquillian-Tests
JB225 Schulung enth¨alt Arquillian- und Drone-Tests
Arquillian und Erweiterungen sehr leistungsf¨ahig und
interessant
Mein Rat: fangen Sie an !
Bernd M¨uller, JAX 2014, 15.5.2014 59/61
Zusammenfassung und (pers¨onliches) Fazit
Einerseits . . .
EAP Dokumentation enth¨alt kein Kapitel zu Arquillian
JBoss Dokumentation enh¨alt kein Kapitel zu WARP
Andererseits . . .
EAP Quickstarts enthalten Arquillian-Tests
JB225 Schulung enth¨alt Arquillian- und Drone-Tests
Arquillian und Erweiterungen sehr leistungsf¨ahig und
interessant
Mein Rat: fangen Sie an !
Bernd M¨uller, JAX 2014, 15.5.2014 59/61
Zusammenfassung und (pers¨onliches) Fazit
Einerseits . . .
EAP Dokumentation enth¨alt kein Kapitel zu Arquillian
JBoss Dokumentation enh¨alt kein Kapitel zu WARP
Andererseits . . .
EAP Quickstarts enthalten Arquillian-Tests
JB225 Schulung enth¨alt Arquillian- und Drone-Tests
Arquillian und Erweiterungen sehr leistungsf¨ahig und
interessant
Mein Rat: fangen Sie an !
Bernd M¨uller, JAX 2014, 15.5.2014 59/61
Zusammenfassung und (pers¨onliches) Fazit
Einerseits . . .
EAP Dokumentation enth¨alt kein Kapitel zu Arquillian
JBoss Dokumentation enh¨alt kein Kapitel zu WARP
Andererseits . . .
EAP Quickstarts enthalten Arquillian-Tests
JB225 Schulung enth¨alt Arquillian- und Drone-Tests
Arquillian und Erweiterungen sehr leistungsf¨ahig und
interessant
Mein Rat: fangen Sie an !
Bernd M¨uller, JAX 2014, 15.5.2014 59/61
Referenzen
Arquillian Reference Guide
JSF Testing
John D. Ament. Arquillian Testing Guide. Packt Publishing,
2013.
Bernd M¨uller, JAX 2014, 15.5.2014 60/61
Fragen und Anmerkungen
Bernd M¨uller, JAX 2014, 15.5.2014 61/61

Drohnen und WARP-Antriebe

  • 2.
    — Drohnen undWARP-Antriebe — JSF-Anwendungen mit Arquillian Drone und Arquillian WARP testen Bernd M¨uller, JAX 2014, 15.5.2014 2/61
  • 3.
  • 4.
    Vorstellung Referent Prof. Informatik(Ostfalia, HS Braunschweig/Wolfenb¨uttel) Buchautor (JSF, Seam, JPA, ...) Mitglied EGs JSR 344 (JSF 2.2) und JSR 338 (JPA 2.1) Gesch¨aftsf¨uhrer PMST GmbH . . . Bernd M¨uller, JAX 2014, 15.5.2014 4/61
  • 5.
    Arquillian Bernd M¨uller, JAX2014, 15.5.2014 5/61
  • 6.
    Arquillian in derSelbstdarstellung Auszug aus http://www.arquillian.org/ So you can rule your code. Not the bugs. No more mocks. No more container lifecycle and deployment hassles. Just real tests! Bernd M¨uller, JAX 2014, 15.5.2014 6/61
  • 7.
    Kurzbeschreibung Arquillian JBoss’ Test-Frameworkf¨ur Tests im Container Dazu JUnit oder TestNG als Test-Runner Und Test-Enricher, um Tests im Container laufen zu lassen Und ShrinkWrap als Werkzeug f¨urs Packaging/Deployment Prinzipieller Ablauf: Test wird auf Client gepackt Test und Laufzeiterweiterung wird im Container deployt Test wird ausgef¨uhrt Testergebnisse werden an Client zur¨uckgegeben Test wird undeployt Aktuell: Arquillian Core Version 1.1.4.Final, 31.3.2014 Bernd M¨uller, JAX 2014, 15.5.2014 7/61
  • 8.
    Kurzbeschreibung Arquillian JBoss’ Test-Frameworkf¨ur Tests im Container Dazu JUnit oder TestNG als Test-Runner Und Test-Enricher, um Tests im Container laufen zu lassen Und ShrinkWrap als Werkzeug f¨urs Packaging/Deployment Prinzipieller Ablauf: Test wird auf Client gepackt Test und Laufzeiterweiterung wird im Container deployt Test wird ausgef¨uhrt Testergebnisse werden an Client zur¨uckgegeben Test wird undeployt Aktuell: Arquillian Core Version 1.1.4.Final, 31.3.2014 Bernd M¨uller, JAX 2014, 15.5.2014 7/61
  • 9.
    Kurzbeschreibung Arquillian JBoss’ Test-Frameworkf¨ur Tests im Container Dazu JUnit oder TestNG als Test-Runner Und Test-Enricher, um Tests im Container laufen zu lassen Und ShrinkWrap als Werkzeug f¨urs Packaging/Deployment Prinzipieller Ablauf: Test wird auf Client gepackt Test und Laufzeiterweiterung wird im Container deployt Test wird ausgef¨uhrt Testergebnisse werden an Client zur¨uckgegeben Test wird undeployt Aktuell: Arquillian Core Version 1.1.4.Final, 31.3.2014 Bernd M¨uller, JAX 2014, 15.5.2014 7/61
  • 10.
    Container, Deployments, Protokolle,Adapter 3 Betriebsmodi Embedded Container Managed Container Remote Container Protokolle Local (embedded) Servlet 2.5 / 3.0 JMX (nur JBoss) Container-Adapter JBoss-AS 4,5,6,7,8 Tomcat, Jetty GlassFish WebLogic WebSphere Im Zweifel: googeln und ausprobieren Bernd M¨uller, JAX 2014, 15.5.2014 8/61
  • 11.
    Container, Deployments, Protokolle,Adapter 3 Betriebsmodi Embedded Container Managed Container Remote Container Protokolle Local (embedded) Servlet 2.5 / 3.0 JMX (nur JBoss) Container-Adapter JBoss-AS 4,5,6,7,8 Tomcat, Jetty GlassFish WebLogic WebSphere Im Zweifel: googeln und ausprobieren Bernd M¨uller, JAX 2014, 15.5.2014 8/61
  • 12.
    Container, Deployments, Protokolle,Adapter 3 Betriebsmodi Embedded Container Managed Container Remote Container Protokolle Local (embedded) Servlet 2.5 / 3.0 JMX (nur JBoss) Container-Adapter JBoss-AS 4,5,6,7,8 Tomcat, Jetty GlassFish WebLogic WebSphere Im Zweifel: googeln und ausprobieren Bernd M¨uller, JAX 2014, 15.5.2014 8/61
  • 13.
    Beispiel: Test-Runner undDeployment @RunWith(Arquillian.class) public class CustomerServiceTest { @Deployment public static Archive <?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , "test.war") .addClasses(Customer.class , CustomerService .class) .addAsResource("META -INF/persistence.xml") . addAsWebInfResource ( new File("src/main/webapp/WEB -INF/beans.xml")); } ... Bernd M¨uller, JAX 2014, 15.5.2014 9/61
  • 14.
    Beispiel: Test-Runner undDeployment @RunWith(Arquillian.class) public class CustomerServiceTest { @Deployment public static Archive <?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , "test.war") .addClasses(Customer.class , CustomerService .class) .addAsResource("META -INF/persistence.xml") . addAsWebInfResource ( new File("src/main/webapp/WEB -INF/beans.xml")); } ... Bernd M¨uller, JAX 2014, 15.5.2014 9/61
  • 15.
    ShrinkWrap Werkzeug zur Erstellung/Manipulationvon Java-Archiven (JARs, WARs, EARs) Fr¨uher eigenst¨andiges JBoss-Projekt, jetzt Arquillian-Teilprojekt Fluent-API zum Erstellen eines Archives, f¨ur sogenannte Micro Deployment, im Beispiel zwei Klassen und Deployment-Descriptoren Bernd M¨uller, JAX 2014, 15.5.2014 10/61
  • 16.
    Verbesserungspotenzial @Deployment public static Archive<?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , generatedName) .addPackage(true , Customer.class.getPackage ()) .addAsResource("META -INF/test -persistence.xml", "META -INF/persistence.xml") . addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml"); } Generierter Deployment-Name Ganzes Package, optional mit Sub-Packages Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . ) Leerer Deployment-Descriptor, auch String-Asset Bernd M¨uller, JAX 2014, 15.5.2014 11/61
  • 17.
    Verbesserungspotenzial @Deployment public static Archive<?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , generatedName) .addPackage(true , Customer.class.getPackage ()) .addAsResource("META -INF/test -persistence.xml", "META -INF/persistence.xml") . addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml"); } Generierter Deployment-Name Ganzes Package, optional mit Sub-Packages Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . ) Leerer Deployment-Descriptor, auch String-Asset Bernd M¨uller, JAX 2014, 15.5.2014 11/61
  • 18.
    Verbesserungspotenzial @Deployment public static Archive<?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , generatedName) .addPackage(true , Customer.class.getPackage ()) .addAsResource("META -INF/test -persistence.xml", "META -INF/persistence.xml") . addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml"); } Generierter Deployment-Name Ganzes Package, optional mit Sub-Packages Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . ) Leerer Deployment-Descriptor, auch String-Asset Bernd M¨uller, JAX 2014, 15.5.2014 11/61
  • 19.
    Verbesserungspotenzial @Deployment public static Archive<?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , generatedName) .addPackage(true , Customer.class.getPackage ()) .addAsResource("META -INF/test -persistence.xml", "META -INF/persistence.xml") . addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml"); } Generierter Deployment-Name Ganzes Package, optional mit Sub-Packages Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . ) Leerer Deployment-Descriptor, auch String-Asset Bernd M¨uller, JAX 2014, 15.5.2014 11/61
  • 20.
    Verbesserungspotenzial @Deployment public static Archive<?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , generatedName) .addPackage(true , Customer.class.getPackage ()) .addAsResource("META -INF/test -persistence.xml", "META -INF/persistence.xml") . addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml"); } Generierter Deployment-Name Ganzes Package, optional mit Sub-Packages Spezieller Deployment-Descriptor f¨ur Test (JPA, CDI, . . . ) Leerer Deployment-Descriptor, auch String-Asset Bernd M¨uller, JAX 2014, 15.5.2014 11/61
  • 21.
    Beispiel: Zu testendeEJB @Stateless public class CustomerService { @PersistenceContext EntityManager em; public void persist(Customer customer) { em.persist(customer ); } public long getNumberOfCustomers () { return em. createNamedQuery ( "Customer. getNumberOfCustomers ", Long.class ). getSingleResult (); } } Bernd M¨uller, JAX 2014, 15.5.2014 12/61
  • 22.
    Beispiel: Der Test @RunWith(Arquillian.class) publicclass CustomerServiceTest { @Deployment public static Archive <?> createTestArchive () { ...} @Inject CustomerService customerService ; @Test public void testPersist () { Customer customer = new Customer("Firstname", "Lastname" assertNull(customer.getId ()); // ueberfluessig customerService .persist(customer ); assertNotNull(customer.getId ()); } Bernd M¨uller, JAX 2014, 15.5.2014 13/61
  • 23.
    Beispiel: Alternativer Test @Test publicvoid testPersist2 () { Customer customer = new Customer("Firstname", "Lastname" Long before = customerService . getNumberOfCustomers (); customerService .persist(customer ); Long after= customerService . getNumberOfCustomers (); assertTrue("Muss ein Customer mehr sein", before + 1 == after ); } Bernd M¨uller, JAX 2014, 15.5.2014 14/61
  • 24.
    Beispiel: 3. Alternativemit Persistenzkontext @RunWith(Arquillian.class) public class CustomerServiceTest { @PersistenceContext EntityManager em; @Test public void testPersist3 () { Customer customer = new Customer("Firstname", "Lastname" Long before = em. createNamedQuery ( "Customer. getNumberOfCustomers ", Long.class) . getSingleResult (); customerService .persist(customer ); Long after= em. createNamedQuery ( "Customer. getNumberOfCustomers ", Long.class) . getSingleResult (); assertTrue("Muss ein Customer mehr sein", before + 1 == after ); }
  • 25.
    Beispiel: 3. Alternativemit Persistenzkontext @RunWith(Arquillian.class) public class CustomerServiceTest { @PersistenceContext EntityManager em; @Test public void testPersist3 () { Customer customer = new Customer("Firstname", "Lastname" Long before = em. createNamedQuery ( "Customer. getNumberOfCustomers ", Long.class) . getSingleResult (); customerService .persist(customer ); Long after= em. createNamedQuery ( "Customer. getNumberOfCustomers ", Long.class) . getSingleResult (); assertTrue("Muss ein Customer mehr sein", before + 1 == after ); } Existiert, da Test in Container
  • 26.
    ” Richtige Anwendungen“: MultipleDeployments (Doku) @Deployment(name = "dep1", order = 1) public static WebArchive createDep1 () { ... } @Deployment(name = "dep2", order = 2) public static WebArchive createDep2 () { ... } @Test @OperateOnDeployment ("dep1") public void testRunningInDep1 () { ... } @Test @OperateOnDeployment ("dep2") public void testRunningInDep2 () { ... } Bernd M¨uller, JAX 2014, 15.5.2014 16/61
  • 27.
    Erweiterbarkeit Wie alle modernenSysteme/Frameworks besitzt Arquillian ein Service Provider Interface Aktuelle Erweiterungen: Drone (Web-UI) WARP (JSF) Persistence Performance Graphene (UI, AJAX) Seam 2 Bernd M¨uller, JAX 2014, 15.5.2014 17/61
  • 28.
    Arquillian Drone Bernd M¨uller,JAX 2014, 15.5.2014 18/61
  • 29.
    Arquillian Drone Arquillian-Erweiterung f¨urfunktionale Tests Basiert auf Selenium Selenium-Slogan: Selenium automates browsers WebDriver: M¨oglichkeit zur Browser-Steuerung, u.a. mit Java API WebDriver API das einzig neu zu lernende ¨Anderung des prinzipiellen Ablaufs: Tests auf Client Kombination Client und Server m¨oglich Version aktuell: 1.3.0.Final Version 2.0.0.Alpha1 mit ¨uberarbeitetem/entschlacktem API in Entwicklung (von uns nicht verwendet) Bernd M¨uller, JAX 2014, 15.5.2014 19/61
  • 30.
    Die n¨otigen Erweiterungen/¨Anderungen @RunWith(Arquillian.class) publicclass DroneUsedTest { @ArquillianResource URL deploymentURL; @Drone WebDriver driver; @Deployment(testable = false) public static Archive <?> createTestArchive () { ...} @ArquillianResource: das URL des Deployments @Drone: das WebDriver oder DefaultSelenium API Keine Tests im Server Bernd M¨uller, JAX 2014, 15.5.2014 20/61
  • 31.
    Die n¨otigen Erweiterungen/¨Anderungen @RunWith(Arquillian.class) publicclass DroneUsedTest { @ArquillianResource URL deploymentURL; @Drone WebDriver driver; @Deployment(testable = false) public static Archive <?> createTestArchive () { ...} @ArquillianResource: das URL des Deployments @Drone: das WebDriver oder DefaultSelenium API Keine Tests im Server Bernd M¨uller, JAX 2014, 15.5.2014 20/61
  • 32.
    Die n¨otigen Erweiterungen/¨Anderungen @RunWith(Arquillian.class) publicclass DroneUsedTest { @ArquillianResource URL deploymentURL; @Drone WebDriver driver; @Deployment(testable = false) public static Archive <?> createTestArchive () { ...} @ArquillianResource: das URL des Deployments @Drone: das WebDriver oder DefaultSelenium API Keine Tests im Server Bernd M¨uller, JAX 2014, 15.5.2014 20/61
  • 33.
    Die n¨otigen Erweiterungen/¨Anderungen @RunWith(Arquillian.class) publicclass DroneUsedTest { @ArquillianResource URL deploymentURL; @Drone WebDriver driver; @Deployment(testable = false) public static Archive <?> createTestArchive () { ...} @ArquillianResource: das URL des Deployments @Drone: das WebDriver oder DefaultSelenium API Keine Tests im Server Bernd M¨uller, JAX 2014, 15.5.2014 20/61
  • 34.
    Falls nicht nurClient-Tests @RunWith(Arquillian.class) public class DroneUsedTest { @Drone WebDriver driver; @Deployment public static Archive <?> createTestArchive () { ... } @Test @RunAsClient @InSequence (1) public void createCustomer( @ArquillianResource URL url) { @Test // im Server @InSequence (2) public void countCustomers () { ... } Auch Tests im Server m¨oglich, daher Unterscheidung Reihenfolge der Tests (Widerspruch zur reinen Lehre?)
  • 35.
    Falls nicht nurClient-Tests @RunWith(Arquillian.class) public class DroneUsedTest { @Drone WebDriver driver; @Deployment public static Archive <?> createTestArchive () { ... } @Test @RunAsClient @InSequence (1) public void createCustomer( @ArquillianResource URL url) { @Test // im Server @InSequence (2) public void countCustomers () { ... } Auch Tests im Server m¨oglich, daher Unterscheidung Reihenfolge der Tests (Widerspruch zur reinen Lehre?)
  • 36.
    Falls nicht nurClient-Tests @RunWith(Arquillian.class) public class DroneUsedTest { @Drone WebDriver driver; @Deployment public static Archive <?> createTestArchive () { ... } @Test @RunAsClient @InSequence (1) public void createCustomer( @ArquillianResource URL url) { @Test // im Server @InSequence (2) public void countCustomers () { ... } Auch Tests im Server m¨oglich, daher Unterscheidung Reihenfolge der Tests (Widerspruch zur reinen Lehre?)
  • 37.
    Versteht Arquillian Maven’sPOM ? Nein, aber ShrinkWrap Es gibt einen ShrinkWrap-Resolver, der Maven und Gradle unterst¨utzt Jetzt Beispiel: JSF-Seite zur Kundenneuanlage Navigation zu Kundenanlage-Erfolgreich-Seite, falls kein Fehler Test, ob Navigation funktioniert Test, ob Daten im Server Bernd M¨uller, JAX 2014, 15.5.2014 22/61
  • 38.
    Versteht Arquillian Maven’sPOM ? Nein, aber ShrinkWrap Es gibt einen ShrinkWrap-Resolver, der Maven und Gradle unterst¨utzt Jetzt Beispiel: JSF-Seite zur Kundenneuanlage Navigation zu Kundenanlage-Erfolgreich-Seite, falls kein Fehler Test, ob Navigation funktioniert Test, ob Daten im Server Bernd M¨uller, JAX 2014, 15.5.2014 22/61
  • 39.
    Das (fast) kompletteBeispiel (Teil 1) @RunWith(Arquillian.class) public class CreateCustomerTest { private static final String WEBAPP_SRC = "src/main/webapp"; @Drone WebDriver driver; @Inject CustomerRepository customerRepository ; Bernd M¨uller, JAX 2014, 15.5.2014 23/61
  • 40.
    Das (fast) kompletteBeispiel (Teil 2) @Deployment public static Archive <?> createTestArchive () { MavenDependencyResolver resolver = DependencyResolvers .use( MavenDependencyResolver .class) . loadMetadataFromPom ("pom.xml"); return ShrinkWrap.create(WebArchive.class , "test.war") .addPackages (...). addClasses (...) .addAsResource("META -INF/test -persistence.xml", "META -INF/persistence.xml") . addAsWebInfResource ("test -ds.xml") . addAsWebResource (new File(WEBAPP_SRC , "create.xhtml")) . addAsWebResource (new File(WEBAPP_SRC , "customer -created.xhtml")) . addAsWebInfResource (EmptyAsset.INSTANCE , "beans.xml") . addAsWebInfResource ( new StringAsset("<faces -config version ="2.0"/ >"), "faces -config.xml") .addAsLibraries ( resolver.artifact("org.seleniumhq.selenium:selenium -ja . resolveAsFiles ()); }
  • 41.
    Das (fast) kompletteBeispiel (Teil 3) @Test @RunAsClient @InSequence (1) public void createCustomer( @ArquillianResource URL url) { driver.get(url + "create.jsf"); driver.findElement(By.id("create:firstname")) .sendKeys("firstname"); driver.findElement(By.id("create:lastname")) .sendKeys("lastname"); driver.findElement(By.id("create:dob")) .sendKeys("1.1.2000"); driver.findElement(By.id("create:email")) .sendKeys("email"); driver.findElement(By.id("create:password")) .sendKeys("password"); driver.findElement(By.id("create:create")). click (); assertTrue(driver.findElement( By.xpath("// body[contains(text(), ’Kunde angelegt ’)]")) .isDisplayed ()); }
  • 42.
    Das (fast) kompletteBeispiel (Teil 4) @Test // im Server @InSequence (2) public void countCustomers () { assertEquals (1, customerRepository .getCustomers (). size ()); } Bernd M¨uller, JAX 2014, 15.5.2014 26/61
  • 43.
    @Drone im Detail Injectionin Klasse Class-Based Life-Cycle Analog zu @BeforeClass / @AfterClass Injection in Methode Method-based Life-Cycle Analog zu @Before / @After Mehrere Injektionen ¨uber Qualifier m¨oglich Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver, InternetExplorerDriver, SafariDriver Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in Test-Asserts Bernd M¨uller, JAX 2014, 15.5.2014 27/61
  • 44.
    @Drone im Detail Injectionin Klasse Class-Based Life-Cycle Analog zu @BeforeClass / @AfterClass Injection in Methode Method-based Life-Cycle Analog zu @Before / @After Mehrere Injektionen ¨uber Qualifier m¨oglich Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver, InternetExplorerDriver, SafariDriver Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in Test-Asserts Bernd M¨uller, JAX 2014, 15.5.2014 27/61
  • 45.
    @Drone im Detail Injectionin Klasse Class-Based Life-Cycle Analog zu @BeforeClass / @AfterClass Injection in Methode Method-based Life-Cycle Analog zu @Before / @After Mehrere Injektionen ¨uber Qualifier m¨oglich Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver, InternetExplorerDriver, SafariDriver Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in Test-Asserts Bernd M¨uller, JAX 2014, 15.5.2014 27/61
  • 46.
    @Drone im Detail Injectionin Klasse Class-Based Life-Cycle Analog zu @BeforeClass / @AfterClass Injection in Methode Method-based Life-Cycle Analog zu @Before / @After Mehrere Injektionen ¨uber Qualifier m¨oglich Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver, InternetExplorerDriver, SafariDriver Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in Test-Asserts Bernd M¨uller, JAX 2014, 15.5.2014 27/61
  • 47.
    @Drone im Detail Injectionin Klasse Class-Based Life-Cycle Analog zu @BeforeClass / @AfterClass Injection in Methode Method-based Life-Cycle Analog zu @Before / @After Mehrere Injektionen ¨uber Qualifier m¨oglich Verschiedene Driver: WebDriver, FirefoxDriver, ChromeDriver, InternetExplorerDriver, SafariDriver Durch Selenium Unterst¨utzung von XPath-Ausdr¨ucken in Test-Asserts Bernd M¨uller, JAX 2014, 15.5.2014 27/61
  • 48.
    Arquillian WARP Bernd M¨uller,JAX 2014, 15.5.2014 28/61
  • 49.
    Arquillian Warp Client-seitige Testsmit Zusicherungen/Pr¨ufung von Server-seitiger Logik und Zustand Keine weiteren Bibliotheken, wie etwa Selenium, ben¨otigt Kein UI ben¨otigt (Headless) Speziell f¨ur Servlets und Servlet-basierte Systeme gemacht Im Augenblick nur Servlets direkt und JSF 2 unterst¨utzt Arquillian Spring Framework Extension enth¨alt Warp Spring MVC Extension (nicht betrachtet) Offizieller Nachfolger von JSFUnit Aktuell: Version 1.0.0.Alpha7, 11.3.2014 Bernd M¨uller, JAX 2014, 15.5.2014 29/61
  • 50.
    Die prinzipielle Ideehinter WARP Initiierung eines HTTP-Requests auf Client-Seite z.B. mit WebDriver Im selben Request-Zyklus Ausf¨uhren von Server-seitigen Tests im Container Dazu: Initiieren des Request ¨uber Interface Activity Inspizieren des Server-Zustands ¨uber Klasse Inspection Aktivity mit perform()-Methode Inspection mit JUnit/TestNG-Tests zum ” richtigen“ Zeitpunkt optional: Gruppieren und Observieren von Requests Bernd M¨uller, JAX 2014, 15.5.2014 30/61
  • 51.
    Die n¨otigen Erweiterungen/¨Anderungen @WarpTestf¨ur Test-Klasse @RunAsClient f¨ur Test-Klasse @BeforeServlet, @AfterServlet f¨ur Servlet-Tests @BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests Im Folgenden 3 Beispiele Existieren die richtigen Beans? Validierung Navigation Bernd M¨uller, JAX 2014, 15.5.2014 31/61
  • 52.
    Die n¨otigen Erweiterungen/¨Anderungen @WarpTestf¨ur Test-Klasse @RunAsClient f¨ur Test-Klasse @BeforeServlet, @AfterServlet f¨ur Servlet-Tests @BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests Im Folgenden 3 Beispiele Existieren die richtigen Beans? Validierung Navigation Bernd M¨uller, JAX 2014, 15.5.2014 31/61
  • 53.
    Die n¨otigen Erweiterungen/¨Anderungen @WarpTestf¨ur Test-Klasse @RunAsClient f¨ur Test-Klasse @BeforeServlet, @AfterServlet f¨ur Servlet-Tests @BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests Im Folgenden 3 Beispiele Existieren die richtigen Beans? Validierung Navigation Bernd M¨uller, JAX 2014, 15.5.2014 31/61
  • 54.
    Die n¨otigen Erweiterungen/¨Anderungen @WarpTestf¨ur Test-Klasse @RunAsClient f¨ur Test-Klasse @BeforeServlet, @AfterServlet f¨ur Servlet-Tests @BeforePhase, @AfterPhase (6 Phasen) f¨ur JSF-Tests Im Folgenden 3 Beispiele Existieren die richtigen Beans? Validierung Navigation Bernd M¨uller, JAX 2014, 15.5.2014 31/61
  • 55.
    1. Beispiel: Existierendie richtigen Beans? Weld-Manual: Einloggen ¨uber JSF-View-Bean Pr¨ufen auf Benutzername/Passwort ¨uber EJB CDI-produzierte Customer-Instanz im Session-Scope Die Existenz dieser Instanz soll ¨uberpr¨uft werden Bernd M¨uller, JAX 2014, 15.5.2014 32/61
  • 56.
    JSF Login-Bean @Named @SessionScoped public classLogin implements Serializable { @Inject Credentials credentials; @Inject CustomerService customerService ; private Customer loggedInCustomer ; ... Bernd M¨uller, JAX 2014, 15.5.2014 33/61
  • 57.
    JSF Login-Bean (cont’d) publicvoid login () { loggedInCustomer = customerService .getCustomer (... if ( loggedInCustomer == null) { FacesMessage message = new FacesMessage("Falsche ..."); FacesContext. getCurrentInstance (). addMessage (...); } } @Produces @LoggedIn Customer getloggedInCustomer () { return loggedInCustomer ; } public void logout () { loggedInCustomer = null; } Bernd M¨uller, JAX 2014, 15.5.2014 34/61
  • 58.
    Logged-In-Test @RunWith(Arquillian.class) @WarpTest @RunAsClient public class LoggedInTest{ @Deployment public static Archive <?> createTestArchive () { // nichts besonderes } @ArquillianResource URL contextPath; @Drone WebDriver browser; Bernd M¨uller, JAX 2014, 15.5.2014 35/61
  • 59.
    Logged-In-Test (cont’d) @Test public voidtestLoggedIn () { browser.navigate ().to(contextPath + "login.jsf"); browser.findElement(By.id("form:email")). sendKeys(EMAIL ); browser.findElement(By.id("form:password")). sendKeys(PASSW Warp .initiate(new Activity () { public void perform () { browser.findElement(By.id("form:login")). click (); }}) .inspect(new Inspection () { private static final long serialVersionUID = 1L; @Inject @LoggedIn Customer customer; Bernd M¨uller, JAX 2014, 15.5.2014 36/61
  • 60.
    Struktur zur Verdeutlichung Warp .initiate(newActivity () { ... }) .inspect(new Inspection () { ... }) Aktivit¨at auf dem Client initiieren Inspektion auf dem Server ausf¨uhren Bernd M¨uller, JAX 2014, 15.5.2014 37/61
  • 61.
    Logged-In-Test (cont’d) Warp .initiate(new Activity() {...} ) .inspect(new Inspection () { private static final long serialVersionUID = 1L; @Inject @LoggedIn Customer customer; @BeforePhase(Phase. INVOKE_APPLICATION ) public void noCustomerExists () { Assert.assertNull( "LoggedIn Customer darf nicht existieren", customer ); } ... Bernd M¨uller, JAX 2014, 15.5.2014 38/61
  • 62.
    Logged-In-Test (cont’d) @BeforePhase(Phase. INVOKE_APPLICATION) public void noCustomerExists () { Assert.assertNull( "LoggedIn Customer darf nicht existieren", customer ); } @AfterPhase(Phase. INVOKE_APPLICATION ) public void loggedInCustomerExists () { Assert.assertNotNull( "LoggedIn Customer muss existieren", customer ); Assert.assertEquals("Falsche E-Mail", EMAIL , customer.getEmail ()); Assert.assertEquals("Falsches Passwort", PASSWORD , customer.getPassword ()); } Bernd M¨uller, JAX 2014, 15.5.2014 39/61
  • 63.
    Logged-In-Test (cont’d) @BeforePhase(Phase. INVOKE_APPLICATION) public void noCustomerExists () { Assert.assertNull( "LoggedIn Customer darf nicht existieren", customer ); } @AfterPhase(Phase. INVOKE_APPLICATION ) public void loggedInCustomerExists () { Assert.assertNotNull( "LoggedIn Customer muss existieren", customer ); Assert.assertEquals("Falsche E-Mail", EMAIL , customer.getEmail ()); Assert.assertEquals("Falsches Passwort", PASSWORD , customer.getPassword ()); } Bernd M¨uller, JAX 2014, 15.5.2014 39/61
  • 64.
    Logged-In-Test (cont’d) @BeforePhase(Phase. INVOKE_APPLICATION) public void noCustomerExists () { Assert.assertNull( "LoggedIn Customer darf nicht existieren", customer ); } @AfterPhase(Phase. INVOKE_APPLICATION ) public void loggedInCustomerExists () { Assert.assertNotNull( "LoggedIn Customer muss existieren", customer ); Assert.assertEquals("Falsche E-Mail", EMAIL , customer.getEmail ()); Assert.assertEquals("Falsches Passwort", PASSWORD , customer.getPassword ()); } Bernd M¨uller, JAX 2014, 15.5.2014 39/61
  • 65.
    2. Beispiel: Validierung Credentialswerden falsch eingegeben (zu kurz) JSF erzeugt in Phase 3 FacesMessage-Instanzen Pr¨ufen vor und nach Phase 3, ob Messages existieren oder nicht Bernd M¨uller, JAX 2014, 15.5.2014 40/61
  • 66.
    Klasse Credentials @Named @RequestScoped public classCredentials { @NotNull @Size(min = 6, max = 30) private String email; @NotNull @Size(min = 6, max = 20) private String password; ... Deutsche Fehlermeldung f¨ur @Size: ”muss zwischen 6 ... Bernd M¨uller, JAX 2014, 15.5.2014 41/61
  • 67.
    Validierungstest @RunWith(Arquillian.class) @WarpTest @RunAsClient public class LoggedInValidationFailedTest{ // nichts besonderes im Deployment @ArquillianResource URL contextPath; @Drone WebDriver browser; ... Bernd M¨uller, JAX 2014, 15.5.2014 42/61
  • 68.
    Validierungstest (cont’d) @Test public voidtestValidation () { browser.navigate ().to(contextPath + "login.jsf"); browser.findElement(By.id("form:email")). sendKeys("short") browser.findElement(By.id("form:password")). sendKeys("shor Warp .initiate(new Activity () { public void perform () { browser.findElement(By.id("form:login")). click (); }}) .inspect(new Inspection () { private static final long serialVersionUID = 1L; ... Bernd M¨uller, JAX 2014, 15.5.2014 43/61
  • 69.
    Validierungstest (cont’d) Warp .initiate(new Activity() {...} ) .inspect(new Inspection () { private static final long serialVersionUID = 1L; @ArquillianResource FacesContext facesContext; @BeforePhase(Phase. PROCESS_VALIDATIONS ) public void noFacesMessage () { Assert.assertEquals("Anzahl Fehler muss 0 sein", 0, facesContext.getMessageList (). size ()); } ... Bernd M¨uller, JAX 2014, 15.5.2014 44/61
  • 70.
    Validierungstest (cont’d) Warp .initiate(new Activity() {...} ) .inspect(new Inspection () { private static final long serialVersionUID = 1L; @ArquillianResource FacesContext facesContext; @BeforePhase(Phase. PROCESS_VALIDATIONS ) public void noFacesMessage () { Assert.assertEquals("Anzahl Fehler muss 0 sein", 0, facesContext.getMessageList (). size ()); } ... FacesContext injizierbar! Bernd M¨uller, JAX 2014, 15.5.2014 44/61
  • 71.
    Validierungstest (cont’d) .inspect(new Inspection() { ... @ArquillianResource FacesContext facesContext; @AfterPhase(Phase. PROCESS_VALIDATIONS ) public void facesMessagesExist () { List <FacesMessage > messages = facesContext.getMessageList (); Assert.assertTrue( facesContext.getMessageList (). size () != 0); for (FacesMessage facesMessage : messages) { Assert.assertTrue("Falsche Fehlermeldung", facesMessage.getSummary () .startsWith("muss zwischen 6")); } } Bernd M¨uller, JAX 2014, 15.5.2014 45/61
  • 72.
    3. Beispiel: Navigationmit Redirect Einfache JSF-Seiten mit Navigation und Redirect Noch nicht erw¨ahntes WARP-Feature: Gruppieren von Inspektionen auf Server basierend auf Request-Folge Pr¨ufen der View-Id nach Restore-View-Phase Bernd M¨uller, JAX 2014, 15.5.2014 46/61
  • 73.
    JSF-Seiten mit Navigation redirect-source.xhtml <h:formid="form"> Seite verwendet #{ redirectSourceBean .name} <br /> <h:commandButton id="redirect" action=" redirect-target ? faces-redirect=true" value="Redirect to ’redirect-target .jsf ’" /> </h:form > redirect-target.xhtml <h:form id="form"> Seite verwendet #{ redirectTargetBean .name} /> </h:form > Bernd M¨uller, JAX 2014, 15.5.2014 47/61
  • 74.
    @RunWith(Arquillian.class) @WarpTest @RunAsClient public class RedirectTest{ @Deployment public static Archive <?> createTestArchive () { return ShrinkWrap.create(WebArchive.class , "redirect -test.war") ... . addAsWebResource (new File(WEBAPP_SRC , "redirect -source.xhtml")) . addAsWebResource (new File(WEBAPP_SRC , "redirect -target.xhtml")) ... } @ArquillianResource URL contextPath; @Drone WebDriver browser; ... Bernd M¨uller, JAX 2014, 15.5.2014 48/61
  • 75.
    Navigationstest (cont’d) @Test public voidtestRedirect () { browser.navigate ().to(contextPath + "redirect -source.jsf") Warp .initiate(new Activity () { public void perform () { browser.findElement(By.id("form:redirect")). click (); }}) .group("redirect -source.jsf") .observe(HttpFilters.request (). index (1)) .inspect(new Inspection () { private static final long serialVersionUID = 1L; @AfterPhase(Phase.RESTORE_VIEW) ... Bernd M¨uller, JAX 2014, 15.5.2014 49/61
  • 76.
    Struktur zur Verdeutlichung Warp .initiate(newActivity () { ... }}) .group("redirect -source.jsf") // nur Doku .observe(HttpFilters.request (). index (1)) .inspect(new Inspection () { ... }) .group("redirect -target.jsf") // nur Doku .observe(HttpFilters.request (). index (2)) .inspect(new Inspection () { ... }) .execute (); Assert.assertTrue(browser.getCurrentUrl () .contains("redirect -target.jsf")); Bernd M¨uller, JAX 2014, 15.5.2014 50/61
  • 77.
    Navigationstest (cont’d) .group("redirect -source.jsf") .observe(HttpFilters.request(). index (1)) .inspect(new Inspection () { private static final long serialVersionUID = 1L; @AfterPhase(Phase.RESTORE_VIEW) public void verifyPage( @ArquillianResource FacesContext facesContext) { Assert.assertEquals("/redirect -source.xhtml", facesContext.getViewRoot (). getViewId ()); } }) Bernd M¨uller, JAX 2014, 15.5.2014 51/61
  • 78.
    Navigationstest (cont’d) .group("redirect -target.jsf") .observe(HttpFilters.request(). index (2)) .inspect(new Inspection () { private static final long serialVersionUID = 1L; @AfterPhase(Phase.RESTORE_VIEW) public void verifyPage( @ArquillianResource FacesContext facesContext) { Assert.assertEquals("/redirect -target.xhtml", facesContext.getViewRoot (). getViewId ()); } }) .execute (); Assert.assertTrue(browser.getCurrentUrl () .contains("redirect -target.jsf")); Bernd M¨uller, JAX 2014, 15.5.2014 52/61
  • 79.
    Auswahl des richtigenRequest Da mehrere Request getriggert werden k¨onnen, muss man den richtigen (den, den man observieren will) ausw¨ahlen Dazu das HttpRequestFilter-Interface Damit spezifiziert man den zu verwendenden HttpRequest der aktuellen Gruppe Bernd M¨uller, JAX 2014, 15.5.2014 53/61
  • 80.
    Aus ” Dokumentation“ import static org.jboss.arquillian.warp .client.filter.http.HttpFilters.request; //will accept only requests for HTML ... group () .observe(request (). uri (). contains(".html")) // will accept only REST requests for JSON ... group () .observe(request (). header () .containsValue("Accept", "application/json")) // will accept only POST requests ... group () .observe(request (). method (). equal(POST )) Bernd M¨uller, JAX 2014, 15.5.2014 54/61
  • 81.
    Was kann allesinjiziert werden? Injizierbar ¨uber @ArquillianResource Servlet-Ressourcen ServletRequest or HttpServletRequest ServletResponse or HttpServletResponse Bernd M¨uller, JAX 2014, 15.5.2014 55/61
  • 82.
    Was kann allesinjiziert werden? (cont’d) Injizierbar ¨uber @ArquillianResource JSF-Ressourcen FacesContext Application ELContext, ELResolver, ExpressionFactory ExceptionHandler Flash NavigationHandler PartialViewContext RenderKit ResourceHandler StateManager UIViewRoot ViewHandler Bernd M¨uller, JAX 2014, 15.5.2014 56/61
  • 83.
    Wo Licht ist,ist auch Schatten Sehr schlechte Doku Noch viele/schwere Fehler Scheinbar Ein-Mann-Projekt: Luk´aˇs Fryˇc (Project Lead) Bernd M¨uller, JAX 2014, 15.5.2014 57/61
  • 84.
    Dokumentation WARP Bernd M¨uller,JAX 2014, 15.5.2014 58/61
  • 85.
    Zusammenfassung und (pers¨onliches)Fazit Einerseits . . . EAP Dokumentation enth¨alt kein Kapitel zu Arquillian JBoss Dokumentation enh¨alt kein Kapitel zu WARP Andererseits . . . EAP Quickstarts enthalten Arquillian-Tests JB225 Schulung enth¨alt Arquillian- und Drone-Tests Arquillian und Erweiterungen sehr leistungsf¨ahig und interessant Mein Rat: fangen Sie an ! Bernd M¨uller, JAX 2014, 15.5.2014 59/61
  • 86.
    Zusammenfassung und (pers¨onliches)Fazit Einerseits . . . EAP Dokumentation enth¨alt kein Kapitel zu Arquillian JBoss Dokumentation enh¨alt kein Kapitel zu WARP Andererseits . . . EAP Quickstarts enthalten Arquillian-Tests JB225 Schulung enth¨alt Arquillian- und Drone-Tests Arquillian und Erweiterungen sehr leistungsf¨ahig und interessant Mein Rat: fangen Sie an ! Bernd M¨uller, JAX 2014, 15.5.2014 59/61
  • 87.
    Zusammenfassung und (pers¨onliches)Fazit Einerseits . . . EAP Dokumentation enth¨alt kein Kapitel zu Arquillian JBoss Dokumentation enh¨alt kein Kapitel zu WARP Andererseits . . . EAP Quickstarts enthalten Arquillian-Tests JB225 Schulung enth¨alt Arquillian- und Drone-Tests Arquillian und Erweiterungen sehr leistungsf¨ahig und interessant Mein Rat: fangen Sie an ! Bernd M¨uller, JAX 2014, 15.5.2014 59/61
  • 88.
    Zusammenfassung und (pers¨onliches)Fazit Einerseits . . . EAP Dokumentation enth¨alt kein Kapitel zu Arquillian JBoss Dokumentation enh¨alt kein Kapitel zu WARP Andererseits . . . EAP Quickstarts enthalten Arquillian-Tests JB225 Schulung enth¨alt Arquillian- und Drone-Tests Arquillian und Erweiterungen sehr leistungsf¨ahig und interessant Mein Rat: fangen Sie an ! Bernd M¨uller, JAX 2014, 15.5.2014 59/61
  • 89.
    Referenzen Arquillian Reference Guide JSFTesting John D. Ament. Arquillian Testing Guide. Packt Publishing, 2013. Bernd M¨uller, JAX 2014, 15.5.2014 60/61
  • 90.
    Fragen und Anmerkungen BerndM¨uller, JAX 2014, 15.5.2014 61/61