MarsJUG - Une nouvelle vision des tests avec Arquillian

Preview:

DESCRIPTION

La réalisation de tests unitaires est fondamentale pour développer des logiciels de qualité. Cependant, tout miser sur eux est illusoire car il faudra à un moment ou un autre vérifier que les composants interagissent convenablement et que leur intégration dans l'environnement cible fonctionne comme prévu. De plus, si l'application fournit une interface graphique, il faut vérifier si les interactions avec celle-ci sont correctes. Arquillian est une plateforme qui est en train de révolutionner la façon de développer les tests d'intégration et fonctionnels dans le monde Java. Et malgré des défauts de jeunesse, Arquillian permet de faire des tests automatisés de composants et d'applications Java, depuis la persistance jusqu'à l'interface graphique, en couvrant un périmètre qui dépasse largement son cadre initial qui était Java EE. Lors de cette session, vous verrez comment Arquillian est capable de tester : l'intégration de composants Java EE, sur différents serveurs d'applications le code de persistance avec l'extension APE les interfaces Web, en facilitant l'utilisation de Selenium

Citation preview

1Alexis Hassler

Une nouvelle vision des tests avec

MarsJUGseptembre 2013

2

@AlexisHassler

Développeur, formateur Java

Indépendant

Co-leader du

3

Tests

Unitaire Intégration

4

Test unitaire

mockmock

mock

new ClassToBeTested()

mock

5

ContainerEJB

Other BeanJPA

EntityManagerCDI

Bean

TransactionSécurité Intercepteurs

...

Intercepteurs Sécurité

BeanToBeDeployed

JMSQueue

6

Container

Mock

7

Mock

8

Test d'intégration

EJBOther Bean

JPAEntityManager

CDIBean

TransactionSécurité Intercepteurs

...

Intercepteurs Sécurité

BeanToBeDeployed

JMSQueue

9

Tests d'intégration JavaEE

10

Tester des composants

pas des classes isolées

pas l'application complète

11

@RunWith(Arquillian.class)public class GreeterArqIT {

@Deployment public static Archive<?> deploy() { return ShrinkWrap.create(JavaArchive.class) .addClasses(Greeter.class, Location.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }

@Inject Greeter greeter;

@Test public void testGreet() throws Exception { String who = "World"; String expected = "Hi " + who; String actual = greeter.greet(who);

assertEquals(expected, actual); }}

12

@RunWith(Arquillian.class)public class GreeterArqIT {

@Deployment public static Archive<?> deploy() { return ShrinkWrap.create(JavaArchive.class) .addClasses(Greeter.class, Location.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }

@Inject Greeter greeter;

@Test public void testGreet() throws Exception { String who = "World"; String expected = "Hi " + who; String actual = greeter.greet(who);

assertEquals(expected, actual); }}

Runner JUnit

Méthode de test

13

@RunWith(Arquillian.class)public class GreeterArqIT {

@Deployment public static Archive<?> deploy() { return ShrinkWrap.create(JavaArchive.class) .addClasses(Greeter.class, Location.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }

@Inject Greeter greeter;

@Test public void testGreet() throws Exception { String who = "World"; String expected = "Hi " + who; String actual = greeter.greet(who);

assertEquals(expected, actual); }}

Injection de dépendance

14

@RunWith(Arquillian.class)public class GreeterArqIT {

@Deployment public static Archive<?> deploy() { return ShrinkWrap.create(JavaArchive.class) .addClasses(Greeter.class, Location.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }

@Inject Greeter greeter;

@Test public void testGreet() throws Exception { String who = "World"; String expected = "Hi " + who; String actual = greeter.greet(who);

assertEquals(expected, actual); }}

Déploiement du composant

15

@Deployment public static Archive<?> deploy() {

return ShrinkWrap.create(JavaArchive.class)

.addClasses(Greeter.class, Location.class)

.addAsResource("config.properties")

.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");

}

1. Créer l'archive

16

@Deployment public static Archive<?> deploy() {

return ShrinkWrap.create(JavaArchive.class)

.addClasses(Greeter.class, Location.class)

.addAsResource("config.properties")

.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");

}

2. Ajouter du contenu

17

@Deployment public static Archive<?> deploy() {

return ShrinkWrap.create(JavaArchive.class)

.addClasses(Greeter.class, Location.class)

.addAsResource("config.properties")

.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");

}

3. Déployer

18

@Deployment public static Archive<?> deploy() {

File[] requiredLibraries = Maven.resolver() .loadPomFromFile("pom.xml") .importRuntimeAndTestDependencies() .resolve() .withTransitivity() .asFile();

return ShrinkWrap .create(WebArchive.class) ... .addAsLibraries(requiredLibraries); }

Résolution de dépendances Maven

19

Aucune référence au conteneur

dans les tests

20

Weld

Tomcat

OpenWebBeans

OpenEJB

Jetty

Weblogic

Websphere

JBoss AS

Glassfish

TomEE

21

RemoteManaged

Embedded

22

TomcatJetty

Weblogic

Websphere

JBoss AS

Glassfish

TomEE

23

Cloudbees

OpenShift

TomcatJetty

Weblogic

Websphere

JBoss AS

Glassfish

TomEE

24

<dependency> <groupId> org.jboss.arquillian.container </groupId> <artifactId> arquillian-glassfish-embedded-3.1 </artifactId></dependency>

Container

25

Mettre les

tests dans le conteneur plutôt que

gérer le conteneur dans les tests

26

@Deployment public static Archive<?> deploy() { return ShrinkWrap.create(WebArchive.class) .addClasses(Greeter.class, Location.class) .addAsResource("config.properties") .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }

arquillian-*.jar MyArquillianIT.class

27

@RunWith(Arquillian.class)

@Deployment

@EJB, @Inject, @Resource

@Test

28

RemoteManaged

Embedded

29

RemoteManaged

EmbeddedDebug

30

Avec des données

31

@PersistenceContextEntityManager em;

@ResourceUserTransaction tx;

Injection

@Resource(mappedName="java:/jdbc/sample")DataSource ds;

32

Transaction Extension

@Transactional(TransactionMode.ROLLBACK)public class GreeterFromDatabaseIT { ...}

33

Persistence Extension

@UsingDataSet("msg1.yml")

@ShouldMatchDataSet( value="expected-msg.yml", excludeColumns="id")

34

Comme client

35

@RunWith(Arquillian.class)public class GreeterArqIT { @Deployment(testable=false) public static Archive deploy() { ... } @ArquillianResource URL deploymentUrl; @Test public void should_request_get_result() { ... }}

36

@RunWith(Arquillian.class)public class GreeterArqIT { @Deployment(testable=false) public static Archive deploy() { ... } @ArquillianResource URL deploymentUrl; @Test public void should_request_get_result() { ... }}

Déploiement SANS les tests

37

@RunWith(Arquillian.class)public class GreeterArqIT { @Deployment(testable=false) public static Archive deploy() { ... } @ArquillianResource URL deploymentUrl; @Test public void should_request_get_result() { ... }}

Injection de l'URL du déploiement

38

@RunWith(Arquillian.class)public class GreeterArqIT { @Deployment(testable=false) public static Archive deploy() { ... } @ArquillianResource URL deploymentUrl; @Test public void should_request_get_result() { ... }}

HttpUnit, Selenium,...

39

Drone

40

Injection Selenium

@RunWith(Arquillian.class)public class GreeterArqIT { @ArquillianResource URL deploymentUrl;

@Drone WebDriver browser; ...

}

41

Graphene

42

Injection Page Object

@RunWith(Arquillian.class)public class GreeterArqIT { @ArquillianResource URL deploymentUrl;

@Page TalkPage talkPage; ...

}

43

Warp

44

@RunWith(Arquillian.class) @WarpTestpublic class TalkPageWarpIT {

@Deployment(testable = true) public static WebArchive deploy() { return Deployments.prepareDeployment(); }

@ArquillianResource URL baseUrl; @Drone WebDriver browser; @Page TalkPage talkPage;

@Test @RunAsClient public void should_my_talks_have_2_lines() { Warp.initiate(...) .observe(...) .inspect(...); }

}

45

@RunWith(Arquillian.class) @WarpTestpublic class TalkPageWarpIT {

@Deployment(testable = true) public static WebArchive deploy() { return Deployments.prepareDeployment(); }

@ArquillianResource URL baseUrl; @Drone WebDriver browser; @Page TalkPage talkPage;

@Test @RunAsClient public void should_my_talks_have_2_lines() { Warp.initiate(...) .observe(...) .inspect(...); }

}

Drone & Graphene

46

@RunWith(Arquillian.class) @WarpTestpublic class TalkPageWarpIT {

@Deployment(testable = true) public static WebArchive deploy() { return Deployments.prepareDeployment(); }

@ArquillianResource URL baseUrl; @Drone WebDriver browser; @Page TalkPage talkPage;

@Test @RunAsClient public void should_my_talks_have_2_lines() { Warp.initiate(...) .observe(...) .inspect(...); }

}

3 phasesWarp

47

Warp.initiate( new Activity() {

...

})

.observe(...)

.inspect(...);

Activité Coté client

48

Warp.initiate( new Activity() { @Override public void perform() { talkPage.open(); } })

.observe(...)

.inspect(...);

49

Warp.initiate(...)

.observe(...)

.inspect( new Inspection() {

...

});

Inspection Coté serveur

50

Warp.initiate(...)

.observe(...)

.inspect( new Inspection() { @ArquillianResource HttpServletRequest request;

@AfterServlet public void after() { assertEquals(...); } });

51

Warp.initiate(...)

.observe( ...

)

.inspect(...);

Filtre des requêtes

52

Warp.initiate(...)

.observe( HttpFilters.request() .uri() .contains("Hassler") )

.inspect(...);

53

Au delà de Java EE

54

55

56

GAE/

CapeDwarf

57

Conclusion

58

VRAISTESTS

59

Mock

Mock

60

Références

http://arquillian.org

http://github.com/hasalex/arquillian-demo

http://slideshare.com/sewatech

61

@AlexisHassler

http://alexis-hassler.com

alexis.hassler@sewatech.fr

http://sewatech.fr

62?

Recommended