1
Alexis Hassler
Une nouvelle vision des tests
avec
septembre 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
Container
EJB
Other Bean
JPA
EntityManager
CDI
Bean
Transaction
Sécurité Intercepteurs
...
Intercepteurs
Sécurité
BeanToBeDeployed
JMS
Queue
6
Container
Mock
7
Container
8
Mock
9
Test d'intégration
EJB
Other Bean
JPA
EntityManager
CDI
Bean
Transaction
Sécurité Intercepteurs
...
Intercepteurs
Sécurité
BeanToBeDeployed
JMS
Queue
10
Tests d'intégration
JavaEE
11
Tester des composants
pas des classes isolées
pas l'application complète
12
Aucune référence au
conteneur
dans les tests
13
Weld
Tomcat
OpenWebBeans
OpenEJB
Jetty
Weblogic
Websphere
JBoss AS
Glassfish
TomEE
14
Remote
Managed
Embedded
15
TomcatJetty
Weblogic
Websphere
JBoss AS
Glassfish
TomEE
16
Cloudbees
OpenShift
TomcatJetty
Weblogic
Websphere
JBoss AS
Glassfish
TomEE
17
Mettre les
tests dans le conteneur
plutôt que
gérer le conteneur dans les tests
18
@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);
}
}
19
@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
20
@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
21
@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
22
@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
23
@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
24
@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
25
@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
26
@RunWith(Arquillian.class)
@Deployment
@EJB, @Inject, @Resource
@Test
27
Avec des données
28
@PersistenceContext
EntityManager em;
@Resource
UserTransaction tx;
Injection
@Resource(mappedName="java:/jdbc/sample")
DataSource ds;
29
Transaction Extension
@Transactional(TransactionMode.ROLLBACK)
public class GreeterFromDatabaseIT {
...
}
30
Persistence Extension
@UsingDataSet("msg1.yml")
@ShouldMatchDataSet(
value="expected-msg.yml",
excludeColumns="id")
31
Comme client
32
@RunWith(Arquillian.class)
public class GreeterArqIT {
@Deployment(testable=false)
public static Archive deploy() {
...
}
@ArquillianResource URL deploymentUrl;
@Test
public void should_request_get_result() {
...
}
}
33
@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
34
@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
35
@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,...
36
Drone
37
Injection Selenium
@RunWith(Arquillian.class)
public class GreeterArqIT {
@ArquillianResource URL deploymentUrl;
@Drone WebDriver browser;
...
}
38
Graphene
39
Injection Page Object
@RunWith(Arquillian.class)
public class GreeterArqIT {
@ArquillianResource URL deploymentUrl;
@Page TalkPage talkPage;
...
}
40
Warp
41
@RunWith(Arquillian.class)
@WarpTest
public 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(...);
}
}
42
@RunWith(Arquillian.class)
@WarpTest
public 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
43
@RunWith(Arquillian.class)
@WarpTest
public 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 phases
Warp
44
Warp.initiate(
new Activity() {
...
})
.observe(...)
.inspect(...);
Activité
Coté client
45
Warp.initiate(
new Activity() {
@Override
public void perform() {
talkPage.open();
}
})
.observe(...)
.inspect(...);
46
Warp.initiate(...)
.observe(...)
.inspect(
new Inspection() {
...
});
Inspection
Coté serveur
47
Warp.initiate(...)
.observe(...)
.inspect(
new Inspection() {
@ArquillianResource
HttpServletRequest request;
@AfterServlet
public void after() {
assertEquals(...);
}
});
48
Warp.initiate(...)
.observe(
...
)
.inspect(...);
Filtre des
requêtes
49
Warp.initiate(...)
.observe(
HttpFilters.request()
.uri()
.contains("Hassler")
)
.inspect(...);
50
Au delà de
Java EE
51
52
53
GAE
/
CapeDwarf
54
Conclusion
55
VRAIS
TESTS
56
Mock
Mock
57
Références
http://arquillian.org
http://github.com/hasalex/arquillian-demo
http://slideshare.com/sewatech
58
@AlexisHassler
http://alexis-hassler.com
alexis.hassler@sewatech.fr
http://sewatech.fr
59
?

JUG Summer Camp - Une nouvelle vision des tests avec Arquillian