33
Feige sein! Testen im EE-Umfeld Dirk Weil, GEDOPLAN GmbH

Feige sein! Testen im Java-EE-Umfeld

Embed Size (px)

DESCRIPTION

GEDOPLAN-Vortrag zum Thema Unit Tests, Multi Unit Tests und Integration Tests insbesondere für Anwendungen auf Basis der Java EE. (www.gedoplan.de)

Citation preview

Page 1: Feige sein! Testen im Java-EE-Umfeld

Feige sein!

Testen im EE-Umfeld

Dirk Weil, GEDOPLAN GmbH

Page 2: Feige sein! Testen im Java-EE-Umfeld

Dirk Weil

GEDOPLAN GmbH, Bielefeld

Java EE seit 1998

Konzeption und

Realisierung

Vorträge

Seminare

Veröffentlichungen

2 Feige sein!

Page 3: Feige sein! Testen im Java-EE-Umfeld

Testen

3 Feige sein!

Bei mir läuft's!

Dafür haben wir

kein Budget.

Gestern ging‘s

noch (und ich hab‘

nix gemacht).

Wir haben

keinen

Testserver

EE-Tests sind zu

aufwändig.

Page 4: Feige sein! Testen im Java-EE-Umfeld

Testen

4 Feige sein!

Testen ist feige!

… dann lassen Sie uns feige sein!

Page 5: Feige sein! Testen im Java-EE-Umfeld

EE-Tests

Komplexe Komponenten-Landschaft

CDI / EJB

@Inject, @Produces, @Alternative …

Plattform

@PersistenceContext, @Transactional, …

Web

@Named, @XyzScoped, @Path

5 Feige sein!

Page 6: Feige sein! Testen im Java-EE-Umfeld

real

embedded

SE-Test

Was und wie schnell?

6 Feige sein!

Ausf

ühru

ngsz

eit

Testtiefe

Unit

Test

Multi Unit

Test

Integration

Test

Einzelklasse Komponente

Subsystem

Anwendung

Service

(inkl. Umgebung)

In-Container-Test

Page 7: Feige sein! Testen im Java-EE-Umfeld

Beispielprojekt

7 Feige sein!

WaehrungRepository

WaehrungService

WaehrungModel

+ Views

WaehrungRestService

BestellungRepository

ArtikelRepository

ShopModel

+ Views

Artikel

Bestellung

Waehrung

Bestell-

Position

EntityManager / PU TX Manager

Page 8: Feige sein! Testen im Java-EE-Umfeld

Unit Test

Test: Umrechnung in WaehrungService

Mock für WaehrungRepository

Toolset: JUnit, Mockito

8 Feige sein!

WaehrungRepository

WaehrungService Waehrung

Page 9: Feige sein! Testen im Java-EE-Umfeld

Unit Test

9 Feige sein!

@Stateless @LocalBean

public class WaehrungService implements WaehrungServiceRemote

{

@Inject

WaehrungRepository waehrungRepository;

public BigDecimal getTauschkurs(String waehrungId)

{

Waehrung waehrung = waehrungRepository.findById(waehrungId);

public class WaehrungServiceUnitTest

{

@BeforeClass

public static void beforeClass()

{

repository = Mockito.mock(WaehrungRepository.class);

Mockito.when(repository.findById("USD")).thenReturn(USD);

service = new WaehrungService();

service.waehrungRepository = repository;

}

Mock-Objekt vorbereiten

„Injektion“

Page 10: Feige sein! Testen im Java-EE-Umfeld

Multi Unit Test

Test: Umrechnung in WaehrungService

Test-DB statt Prod-DB

Toolset: JUnit, CDI-Container

alternativer Producer für EntityManager

TX-Interceptor

10 Feige sein!

WaehrungRepository

WaehrungService Waehrung

EntityManager / PU TX Manager

Page 11: Feige sein! Testen im Java-EE-Umfeld

Multi Unit Test

Apache

DeltaSpike

Container-

Start

Kontext-

Start

Injektion

in unmanaged

Objects

public class WaehrungServiceMultiTest { private static CdiContainer cdiContainer; @BeforeClass public static void beforeClass() { cdiContainer = CdiContainerLoader.getCdiContainer(); cdiContainer.boot(); cdiContainer.getContextControl().startContexts(); } @Before public void before() { BeanProvider.injectFields(this); } @Inject WaehrungService waehrungService;

Page 12: Feige sein! Testen im Java-EE-Umfeld

Multi Unit Test

Mocking – the CDI way

(1: Alternative)

12 Feige sein!

public class EntityManagerProducer

{

@PersistenceContext(unitName = "seminar")

@Produces

private EntityManager entityManager;

} @Alternative @Priority(1)

public class TestEntityManagerProducer

{

EntityManagerFactory emf;

@PostConstruct

private void postConstruct()

{

emf= Persistence.createEntityManagerFactory("test");

}

@Produces

EntityManager createEntityManager()

{

return emf.createEntityManager();

Mock-Objekt

nur im

Test-Classpath

Page 13: Feige sein! Testen im Java-EE-Umfeld

Multi Unit Test

Mocking – the CDI way

(2: Interceptor)

13 Feige sein!

@Transactional

public class WaehrungRepository

{

public void persist(Waehrung entity)

{

this.entityManager.persist(entity);

@Interceptor @Priority(Interceptor.Priority.APPLICATION + 1)

@Transactional

public class TestTransactionInterceptor

{

@Inject

EntityManager entityManager;

@AroundInvoke

Object manageTX(InvocationContext invocationContext) throws Exception

{

this.entityManager.getTransaction().begin();

Mock-Objekt

nur im

Test-Classpath

Page 14: Feige sein! Testen im Java-EE-Umfeld

Testdaten-Bereitstellung

Bulk Load

Skript, DBUnit, …

Manuell

Prod Extract, …

Anwendungs-API

EntityManager, XyzRepository

14 Feige sein!

<waehrung

id="USD">

>import 2013-11-07.dump

Page 15: Feige sein! Testen im Java-EE-Umfeld

Testdaten-Bereitstellung

Daten vor dem Test löschen …

höhere Komponenten zuerst

… und neu laden

niedere Komponenten zuerst

Daten nach Test stehen lassen!

Lässt sich gut mit CDI implementieren

(Testdaten-Lader wiederum nur im Test-Classpath)

15 Feige sein!

Page 16: Feige sein! Testen im Java-EE-Umfeld

Integration Tests

Test in Java EE Server

Test von Komponenten

inkl. der davon genutzten Schichten

Zugriff auf alle Java-EE-Ressourcen

„echte“ Persistence Unit (mit Test-DB)

„echter“ Transaction Manager

Toolset: JUnit, Arquillian, EE Server

16 Feige sein!

Page 17: Feige sein! Testen im Java-EE-Umfeld

Arquillian

Server Lifecycle (Start/Stop)

Erstellung von Deployment Archives

Deployment (+Undeployment)

Integration mit JUnit und TestNG

Testausführung

Server: White Box Test

Client: Black Box Test

Diverse Erweiterungen

17 Feige sein!

Page 18: Feige sein! Testen im Java-EE-Umfeld

18 Feige sein!

Arquillian

Server starten Archiv erstellen und deployen

Tests durchführen

Archiv undeployen

Server stoppen weitere

Testklasse?

Remote Mode Managed Mode

Page 19: Feige sein! Testen im Java-EE-Umfeld

Arquillian

Container-Wahl durch Classpath

verfügbare Container:

https://docs.jboss.org/author/display/ARQ/Container+adapters

19 Feige sein!

<dependency>

<groupId>org.jboss.arquillian.junit</groupId>

<artifactId>arquillian-junit-container</artifactId>

<scope>test</scope>

</dependency>

<profiles>

<profile>

<id>astest_wildfly-8.0-managed</id>

<dependencies>

<dependency>

<groupId>org.wildfly</groupId>

<artifactId>wildfly-arquillian-container-managed</artifactId>

<scope>test</scope>

</dependency>

Page 20: Feige sein! Testen im Java-EE-Umfeld

Arquillian

JUnit Testrunner

Deployment mit ShrinkWrap erstellen

neuen Archivnamen nutzen (z. B. UUID)

richtige Endung!

20 Feige sein!

@RunWith(Arquillian.class)

public class WaehrungServiceIntegrationTest

{

@Deployment

public static WebArchive createDeployment()

{

WebArchive archive = ShrinkWrap.create(WebArchive.class, deploymentUnitName + ".war");

archive.addClasses(…);

archive.addAsWebInfResource(…);

archive.addAsResource(…);

archive.addAsLibraries(…);

Page 21: Feige sein! Testen im Java-EE-Umfeld

Arquillian

White Box Test

@Deployment(testable=true) (Default)

Testklasse wird mit deployt

@Inject etc. nutzbar

21 Feige sein!

@RunWith(Arquillian.class)

public class WaehrungServiceIntegrationTest

{

@Inject WaehrungService waehrungService;

@Test

public void testUmrechnenUSD()

{

BigDecimal actual = this.waehrungService.umrechnen(fremdBetrag, fremdWaehrungId);

Assert.assertEquals("Euro-Betrag", expected, actual);

Page 22: Feige sein! Testen im Java-EE-Umfeld

Arquillian

White Box Test

Passend erstelltes Deployment

angepasste PU-Definition

22 Feige sein!

WaehrungRepository

WaehrungService Waehrung

EntityManager / PU TX Manager

Page 23: Feige sein! Testen im Java-EE-Umfeld

Arquillian

White Box Test

23 Feige sein!

Archiv erstellen

- Benötigte Anwendungsdateien

- ggf. spezielle Testartefakte

(z.B. persistence.xml)

- Testklasse inkl. Dependencies

(automatisch per testable=true)

Testergebnisse einsammeln

Testlauf abschließen

Archiv deployen

Tests ausführen

Archiv undeployen

Client Server

Page 24: Feige sein! Testen im Java-EE-Umfeld

Arquillian

Black Box Test

@Deployment(testable=false)

Test läuft im Client

(IDE, Jenkins, etc.)

Zugriff nur Remote

z. B. EJB per Remoting

z. B. RESTful Service via JAX-RS Client

24 Feige sein!

@RunWith(Arquillian.class)

public class WaehrungServiceRemoteIntegrationTest

{

@Deployment(testable = false)

public static WebArchive createDeployment()

{

@RunWith(Arquillian.class)

public class WaehrungRestServiceIntegrationTest

{

@Deployment(testable = false)

public static WebArchive createDeployment()

{

Page 25: Feige sein! Testen im Java-EE-Umfeld

Arquillian

Black Box Test

25 Feige sein!

Archiv erstellen

- Benötigte Anwendungsdateien

- ggf. spezielle Testartefakte

(z.B. persistence.xml)

Tests ausführen

Testlauf abschließen

Archiv deployen

Archiv undeployen

Client Server

remote

Page 26: Feige sein! Testen im Java-EE-Umfeld

Drone

Arquillian-Erweiterung für Selenium

Browser-Fernsteuerung

Drone übernimmt Lifecycle-Steuerung des ggf. nötigen Browsers

@Drone injiziert WebDriver (=Fernsteuerung)

Browser wählbar via arquillian.xml

Firefox, Crome, IE, HtmlUnit, PhantomJS, …

häufig per Maven-Profil

26 Feige sein!

Page 27: Feige sein! Testen im Java-EE-Umfeld

Drone

27 Feige sein!

WaehrungRepository

WaehrungService

WaehrungModel

+ Views

EntityManager / PU TX Manager

Waehrung

Page 28: Feige sein! Testen im Java-EE-Umfeld

28 Feige sein!

Drone

@RunWith(Arquillian.class)

public class WaehrungGuiIntegrationTest

{

@Drone WebDriver webDriver;

@Test

public void testUmrechnenUSD()

{

this.webDriver.get(serverUrlWebContext + "/demo/waehrungsrechner.xhtml");

WebElement fremdBetragField = this.webDriver.findElement(By.id("form:fremdBetrag"));

fremdBetragField.clear();

fremdBetragField.sendKeys(fremdBetrag.toString());

WebElement umrechnenButton = this.webDriver.findElement(By.id("form:umrechnen"));

umrechnenButton.click();

WebElement euroBetragField = this.webDriver.findElement(By.id("form:euroBetrag"));

String actual = euroBetragField.getText();

Assert.assertEquals("Eurowert", expected, actual);

Page 29: Feige sein! Testen im Java-EE-Umfeld

Drone

Grey Box Test

Web GUI Fernbedienung wie zuvor

Abfrage des serverseitigen Zustands

z. B. mittels Remote EJB

29 Feige sein!

@RunWith(Arquillian.class)

public class ShopGuiIntegrationTest

{

@Test

public void testCreateBestellung()

{

this.webDriver.get(serverUrlWebContext + "/demo/waehrungsrechner.xhtml");

ShopGuiIntegrationTestInspectorRemote inspector

= ServiceLocator.getEjb(ShopGuiIntegrationTestInspectorRemote.class, …);

Assert.assertTrue("Bestellung nicht gespeichert",

inspector.checkBestellungExists(expected));

Page 30: Feige sein! Testen im Java-EE-Umfeld

Arquillian Extensions

30 Feige sein!

Persistence Initialisierung, Validierung und Cleanup

der Datenbank

JaCoCo Code Coverage Monitoring

Performance Prüfung der Ausführungszeit

Warp Grey Box Testing mit Drone

Graphene Selenium-Erweiterung u. a. mit AJAX-

Unterstützung und JQuery-Selektion

Page 31: Feige sein! Testen im Java-EE-Umfeld

Arquillian Experience

Mächtiges Werkzeug

Dokumentation je nach Extension sehr gut bis nicht vorhanden

Aufwändige Konfiguration

JAR-Hölle

Ausführungsgeschwindigkeit

31 Feige sein!

Page 33: Feige sein! Testen im Java-EE-Umfeld

More

Seminare zum Thema, z. B.

Java Software Testing

http://www.gedoplan-it-training.de

http://www.gedoplan-it-consulting.de

http://javaeeblog.wordpress.com/

http://expertenkreisjava.blogspot.de/

[email protected]

@dirkweil

34 Feige sein! [email protected]