64
ARQUILLIAN IN DER PRAXIS / Stefan Hildebrandt @hildebrandttk 0

ARQUILLIAN IN DER PRAXIS - doag.org · HISTORIE VON ARQUILLIAN Entstand bei der Implementierung des JSR 299 Weiterentwicklung durch JBoss Fokus: Test ihrer Server und Frameworks Euer

Embed Size (px)

Citation preview

ARQUILLIAN IN DERPRAXIS

/ Stefan Hildebrandt @hildebrandttk

0

MEIN EINSTIEG

JAVA 2 EEjUnitClient-zugriff

Proxies im ContainerInitialContextFactory

NameNotFoundExceptionNamingException

RemoteException

J2EE MIT SPRINGwar-Deployment

Projektspezifische "Frameworks"Deployment mit MocksDatenbanksetupTestdaten

spring-test

JAVA EE 6

JAVA EE OHNE SPRING... OHNE SPRINGTEST

WAS NUN?

ARQUILLIAN!

HISTORIE VON ARQUILLIANEntstand bei der Implementierung des JSR 299Weiterentwicklung durch JBoss

Fokus: Test ihrer Server und FrameworksEuer Projektfokus?

FEATURESSteuerung des Container–LebenszyklusErstellung von ArtefaktenInstallieren von ArtefaktenBereitstellung von Komponenten in den TestPlug-in-Konzept für Erweiterungen

EINSATZBEREICHE

UNIT-TESTS

public class PetTypeControllerTest {

@Testpublic void testSwitchSortOrder_ascending_to_descending() { PetTypeController petTypeController = new PetTypeController(SortOrder.ascending);

petTypeController.switchSortOrder();

assertEquals(SortOrder.descending, petTypeController.getPetTypeSortOrder());}

@Testpublic void testSwitchSortOrder_descending_to_ascending() { PetTypeController petTypeController = new PetTypeController(SortOrder.descending);

petTypeController.switchSortOrder();

assertEquals(SortOrder.ascending, petTypeController.getPetTypeSortOrder());}}

UNIT-TESTSKein Arquillian

Zu hohe KomplexitätRelativ langsam

UNIT-TEST... FÜR JAVA EE ELEMENTE

InterceptorDecoratorFilterJSF-Komponenten...

JPATDD / BDD

Entwicklung von komplexen MappingsSchrittweise Erstellung von QueriesAls Input- -> Output-TestsSehr gute Absicherung für Refactorings

@RunWith(Arquillian.class)@PersistenceTest@UsingDataSet("OwnerDaoImplTest.yml")@Cleanup(strategy = CleanupStrategy.USED_TABLES_ONLY)public class OwnerDaoImplTest {

//Need this instance for arquillian-dbunit loading @PersistenceContext(unitName = "javaee7petclinic") private EntityManager entityManager;

@Inject private OwnerDao ownerDao;

types: - id: 1 name: Katze - id: 2 name: Hundowners: - id: 1 first_name: Stefan last_name: Hildebrandt address: Hauptstr. city: Oldenburg telephone: 0441-666 - id: 2 first_name: Horst last_name: Müller address: Hauptstr. city: Oldenburg telephone: 0441-765pets: - id: 11 name: Speedy birth_date: 2015-01-01 type_id: 1 owner_id: 1 - id: 21 name: Bruno birth_date: 2014-03-04 type_id: 2 owner_id: 2visits: - id: 110 visit_date: 2015-01-11 description: Untersuchungen

@Testpublic void testFindOwnersWithVisitWithinGivenTimeFrame_DayForLastVisit() { final List<Owner> owners = ownerDao.findOwnersWithVisitWithinGivenTimeFrame( SIMPLE_DATE_FORMAT.parse("2015-03-11"), new Date()); assertThat(owners, CoreMatchers .<Owner>hasItem(hasProperty("firstName", is(equalTo("Stefan"))))); assertThat(owners, not(CoreMatchers .<Owner>hasItem(hasProperty("firstName", is(equalTo("Horst"))))));}

@Testpublic void testFindOwnersWithVisitWithinGivenTimeFrame_OnlyOneVisitOnOneDayInPast() { final List<Owner> owners = ownerDao.findOwnersWithVisitWithinGivenTimeFrame( SIMPLE_DATE_FORMAT.parse("2015-03-10"), SIMPLE_DATE_FORMAT.parse("2015-03-10")); assertThat(owners, not(CoreMatchers .<Owner>hasItem(hasProperty("firstName",is(equalTo("Stefan")))))); assertThat(owners, CoreMatchers .<Owner>hasItem(hasProperty("firstName", is(equalTo("Horst")))));}

@Testpublic void testFindOwnersWithVisitWithinGivenTimeFrame_AllVisitsUntilSomeDateInPast() { final List<Owner> owners = ownerDao .findOwnersWithVisitWithinGivenTimeFrame( SIMPLE_DATE_FORMAT.parse("1990-03-10"), SIMPLE_DATE_FORMAT.parse("2015-03-10")); assertThat(owners, CoreMatchers .<Owner>hasItem(hasProperty("firstName", is(equalTo("Stefan"))))); assertThat(owners, CoreMatchers .<Owner>hasItem(hasProperty("firstName", is(equalTo("Horst")))));}

SERVICESZusammenspiel mehrerer Elemente eines ServicesMit/ohne DatenbankMocks oder Simulatoren

Angepasstes Deployment@Alternative

@RunWith(Arquillian.class)public class VetWebserviceTest { private static final String BASE = "../../../../"; private static final String POM_PATH = BASE + "pom.xml";

@Deployment(testable = false) public static WebArchive createDaoDeployment() { File[] deps = Maven.resolver().loadPomFromFile(POM_PATH) .importRuntimeDependencies().resolve().withTransitivity().asFile(); WebArchive war; = ShrinkWrap.create(WebArchive.class, "remote-service-deployment.war") .addClasses(VetWebservice.class, JaxRsActivator.class, Vets.class) .addClasses(VetDao.class, Vet.class, Specialty.class) .addClasses(VetDaoMock.class) .addAsLibraries(deps); return war }

@Test@RunAsClientpublic void testFeed() throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); final String uri = baseURL + "rest/vets/feed"; HttpGet httpGet = new HttpGet(uri); CloseableHttpResponse response = httpClient.execute(httpGet); assertEquals(200, response.getStatusLine().getStatusCode()); final String datePattern = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm'.*'").format(new Date()) final HttpEntity entity = response.getEntity(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); entity.writeTo(outputStream); assertThat(outputStream.toString(), RegexMatcher.matchesRegex( "..."));}

SYSTEMDB mit Echtdaten (obfuscated) in VM / ContainerSimulatoren für NachbarsystemeTestschnittstellen:

Service-EbeneRemoteLocal

UI

DEMO UI-TEST

SYSTEMINTEGRATIONMIT NACHBARSYSTEMEN

Komplett definierter und exklusiver StandKein Setup über reguläre UI/ServicesSehr robuste und verlässliche TestsRelativ schnellIdealerweise Ausführung im CI vor Integration

z.B. mit oder (mit )Simulatoren für nicht verfügbare Systeme (SAP, ...)

vagrant docker compose

AKZEPTANZTESTSExterne, fachliche Sicht auf TestsVerlinkung zu AnforderungenLangfristige Absicherung von AnforderungenKlassische Probleme:

LangsamSeltene AusführungWeit weg vom CodeKaum Feedback für Entwicklung

CUKESPACECucumber-Runner für ArquillianAkzeptanztests von Unit- bis SystemintegrationsebeneSetup wie bei Systemintegrationstests

Wesentlich RobusterLokale Ausführung im CI -> Schnelles FeedbackRegelmäßige Ausführung im CI -> Schnelles FeedbackEigener Vortrag

NICHT-FUNKTIONALETESTS

Mit JMeter...Über Messpunkte bei der TestausführungIndirekt: Laufzeit einer größeren Suite

ZUSAMMENFASSUNG EINSATZBEREICHETests immer auf kleinstmöglicher EbeneErst bei konkreten Problemen Tests in höherer EbeneWenige vollumfängliche IntegrationstestsDurch die integrierte Kombination wertvoll

CLIENT-/SERVER-MODE

CLIENT@Deployment(testable = false)Nur Deployment des ArchivsTests laufen in der Client-JVM

SERVER@DeploymentArchiv wird erweitertTests laufen im ContainerÜbertragung der Ergebnisse an den TestVoller Zugriff auf Ressourcen/Komponenten

CONTAINERMANAGEMENT

REMOTEVerwendung einer bestehenden laufenden Instanz➚ Am schnellsten➚ Ergebnis realitätsnah➘ Manuelles Setup➘ Manuelles Starten/Stoppen➘ Hängenbleiben von Deployments

MANAGEDVerwendung einer bestehenden InstallationStart/Stop durch Arquillian➚ Ergebnis realitätsnah➚ Automatisches Starten/Stoppen➘ Etwas längere Laufzeiten➘ Manuelles Setup➘ Hängenbleiben von Deployments

EMBEDDEDVerwendung eines embedded-Containers in der Test-JVM➚ Kein Hängenbleiben von Deployments➚ Automatisches Startup➚ Automatisches Setup➘ Etwas längere Laufzeiten➘ Ergebnis ggf. nicht vollständig realitätsnah➘ Konflikte von Bibliotheken (z.B. guava)

DEBUGGING➚ Embedded: Alles➙ Client: Nur den Test➘ Ansonsten: Remote-Debugging

ARTEFAKT-ERSTELLUNG

SHRINKWRAPErstellung von ArtefaktenProgrammatischSehr flexibel -> Gut für Unit-tests

DOPPLUNG DERBUILDSYSTEMBESCHREIBUNG➚ Maven/Gradle-Importer➘ Resources, Pre-/Postprocessing, ...

AUSFÜHRUNGSZEIT

DEPLOYMENTEin Deployment je Testklasse➙ Unit-Test➘ Integrationstests

ARQUILLIAN SUITE EXTENSIONIdee: Ein Deployment je Test-Classpath

Auswirkungen auf ProjektlayoutAlternativ: Mehrere Deployments

Benannte DeploymentsZuordnung über Namen

Eigene Events für HooksNicht im Fokus anderer der Kernentwicklung und andererExtensions

Kompatibilitätsprobleme mit anderen Extensions

DEPENDENCY HANDLINGmaven-/gradle-Importer

Analyse komplexer Projekte dauertAlternativ: directory-Importer

Befüllung mittels maven/gradle

DATENBANK SETUP (UNIT)In-Memory-DatenbankenGgf. Testbezogen laden

DATENBANK SETUP (INTEGRATION+)Once-Per-SuiteDedizierte Daten je TestMögliche Verfahren

DB UnitSpezialwerkzeuge für DatenbankenFertige Container oder VMs

UI-TESTSDefinierter Systemzustand

DatenbankSonstige Daten/Zustände

Langsamere Systeme mockenInspections in den MocksBedienung des UIs vereinfachen

MULTI-THREADINGViel KomplexitätAb 4 Threads deutlicher GewinnInterne vs. externe Lösung

INTERNES MULTITHREADINGParallele Ausführung der Tests in eine Suite in einer VMNotwendig:

Synchronisatisiertes Suite-DeploymentDisjunkte TestdatenThreadsave Mocks-/Simulatoren

Nicht mit Arquillian kombinierbarjunittoolbox-ParallelSuite

EXTERNES MULTITHREADINGParallele Testausführung mit maven/gradle

mehrere JVMsNotwendig:

Mehrere Container, DBs und UmsystemeArquillian Cube Extension

INTERESSANTEERWEITERUNGEN

/DRONE GRAPHENEUnterstützung für SeleniumtestsBereitstellung von Webdriver-InstanzImplementierung des Page-Objekt-PatternsErweiterung des Page-Objekt-Patterns um KomponentenEigener Vortrag

WARPUntersuchung von Servlet-Requests im TestMocking von Servlet-Responses im Test

TRANSACTIONTransaktionssteuerung in Tests

PERSISTENCEAusführung von SQL-Skripten für das SchemaDBUnit-Integration

Befüllung einer DBAssert auf DB-Ebene

DOKUMENTATIONQuellcode der TestsQuellcode der Tests von Open Source Projekten

Offizielle GuidesArquillian Showcase

ZUSAMMENFASSUNG➚ Ideal für Java EE-Unit-Tests➚ Auf allen Teststufen verwendbar➚ Viel Flexibilität➘ Viel Komplexität➘ Suite nicht im Fokus

STEFAN HILDEBRANDT - CONSULTING.HILDEBRANDT.TKBeratung, Coaching und ProjektunterstützungJava EEBuildsysteme gradle und maven/ant-MigrationTestautomatisierungCoach in agilen ProjektenDevOps