Documentos de Académico
Documentos de Profesional
Documentos de Cultura
The first test Creating the archive Create the archive using ShrinkWrap Create the archive using maven Configuring Arquillian Configuring the runtime modes of arquillian Managed container config Embedded container config Including persistency (extension) Creating test data manually Creating test data by SQL script Creating test data by means of JSON/XML (or YML) Some kind of round trip
Preface
This is a paper provided by Brockhaus Group for free. All content was checked and all code was tested carefully; in case of questions of suggestions to improve we will be happy to receive you email at: getKnowledge@brockhaus-group.com
Targeted audience
People interested in using Arquillian with a sound knowledge in Java EE technologies, this paper wont explain the details of the Java EE platform. The examples have been tested using JBoss EAP 6.1.1 and the H2 database.
Why Arquillian?
Testing of complex. multi-layered Java EE applications still is pretty difficult as in many cases the services offered by the container needs to be in place. Just think of CDI, various annotations, datasources and so on. One might say, that mocking might replace these concerns and partially this is correct but still there is a gap between what is provided and what is expected. Arquillian tries to close this gap by: maintaining the life-cycle of of a container (and despite the fact Arquillian is a JBoss project there are more containers supported than just JBoss1 ) combining all resources to a deployable artifact and providing some facilities to deploy these
Several plugins are available: Drone (includes Selenium to test the UI as well) Persistence (to create test data out of various formats like XML and JSON) Jacoco (to get some metrics about code coverage)
The only remarkable things are the @ R u n W i t h ( A r q u i l l i a n . c l a s s )and the @ D e p l o y m e n t annotations. Regarding the @ R u n W i t hannotation we should not spent too many words, The @ D e p l o y m e n t annotation looks much more interesting as it seems as if some groundwork is laid in there.
1
We have made use of some kind of helper to create the archive as there are two options which will be explained in more detail.
As you can see easily, every class, deployment descriptor and so on is added on the fly. For your convenience the code to write the created archive to the file system is included. This was proven helpful just to check, whether everything is included properly. IMHO the only disadvantage might be the vast amount of classes in an average project so we were pretty confident there must be another way of getting the archive.
One of the de-facto standards in build tools is maven, so why not making use of the famous m v n c l e a np a c k a g eto get the things done? The following snippet describes how to get the archive loaded into arquillian.
/ * *m a v e nd i di tf o ru s. .w ej u s th a v et or e a dt h ef i l e* / p r i v a t es t a t i cA r c h i v e < ? >g e t A r c h i v e F r o m F i l e ( ){ J a v a A r c h i v ea r t i f a c t=S h r i n k W r a p . c r e a t e ( Z i p I m p o r t e r . c l a s s ,A R C H I V E _ N A M E ) . i m p o r t F r o m ( A R C H I V E _ F I L E ) . a s ( J a v a A r c h i v e . c l a s s ) ; r e t u r na r t i f a c t ; }
Configuring Arquillian
The initial thing we should tell Arquillian is where to find JBoss, therefore a small xml file named a r q u i l l i a n . x m lneeds to put aside of your application.
< ? x m lv e r s i o n = " 1 . 0 " ? > < a r q u i l l i a nx m l n s : x s i = " h t t p : / / w w w . w 3 . o r g / 2 0 0 1 / X M L S c h e m a i n s t a n c e " x m l n s = " h t t p : / / j b o s s . o r g / s c h e m a / a r q u i l l i a n " x s i : s c h e m a L o c a t i o n = " h t t p : / / j b o s s . o r g / s c h e m a / a r q u i l l i a n h t t p : / / j b o s s . o r g / s c h e m a / a r q u i l l i a n / a r q u i l l i a n _ 1 _ 0 . x s d " > < d e f a u l t P r o t o c o lt y p e = " S e r v l e t3 . 0 "/ > < ! f o ra d d i t i o n a li n f os e e : h t t p s : / / d o c s . j b o s s . o r g / a u t h o r / d i s p l a y / A R Q / C o n t a i n e r + c o n f i g u r a t i o n > < c o n t a i n e rq u a l i f i e r = " j b o s s "d e f a u l t = " t r u e " > < c o n f i g u r a t i o n > < ! -t h i sp o i n t st oa ne x i s t i n gi n s t a l l a t i o n ,t a k ec a r ef o r e v e r y t h i n gt ob es e tu pp r o p e r l y ,e s p .t h ed a t a s o u r c e s> < p r o p e r t y n a m e = " j b o s s H o m e " > D : \ a b c \ x y z \ j b o s s e a p 6 . 1 < / p r o p e r t y > < / c o n f i g u r a t i o n > < / c o n t a i n e r > < / a r q u i l l i a n >
Be aware of JBoss configured according to your needs, no topic or queue, no data source means no topic or queue or data source available at testing time. The runtime selection is explained in more detail here.
As we suppose youre making use of maven, here are the dependencies you will need to make the test run:
< d e p e n d e n c i e s > < d e p e n d e n c y > < g r o u p I d > j a v a x < / g r o u p I d > < a r t i f a c t I d > j a v a e e a p i < / a r t i f a c t I d > < v e r s i o n > 6 . 0 < / v e r s i o n > < / d e p e n d e n c y > < d e p e n d e n c y > < g r o u p I d > o r g . j b o s s . s p e c < / g r o u p I d > < a r t i f a c t I d > j b o s s j a v a e e 6 . 0 < / a r t i f a c t I d > < v e r s i o n > 3 . 0 . 2 . F i n a l < / v e r s i o n > < t y p e > p o m < / t y p e > < / d e p e n d e n c y > < d e p e n d e n c y > < g r o u p I d > j u n i t < / g r o u p I d > < a r t i f a c t I d > j u n i t < / a r t i f a c t I d > < v e r s i o n > 4 . 1 1 < / v e r s i o n > < / d e p e n d e n c y > < d e p e n d e n c y > < g r o u p I d > x a l a n < / g r o u p I d > < a r t i f a c t I d > x a l a n < / a r t i f a c t I d > < v e r s i o n > 2 . 7 . 1 < / v e r s i o n > < s c o p e > p r o v i d e d < / s c o p e > < / d e p e n d e n c y > < d e p e n d e n c y > < g r o u p I d > o r g . j b o s s . a r q u i l l i a n . j u n i t < / g r o u p I d > < a r t i f a c t I d > a r q u i l l i a n j u n i t c o n t a i n e r < / a r t i f a c t I d > < v e r s i o n > 1 . 1 . 2 . F i n a l < / v e r s i o n > < s c o p e > t e s t < / s c o p e > < / d e p e n d e n c y > < d e p e n d e n c y > < g r o u p I d > o r g . j b o s s . a r q u i l l i a n . p r o t o c o l < / g r o u p I d > < a r t i f a c t I d > a r q u i l l i a n p r o t o c o l s e r v l e t < / a r t i f a c t I d > < v e r s i o n > 1 . 1 . 2 . F i n a l < / v e r s i o n > < s c o p e > t e s t < / s c o p e > < / d e p e n d e n c y > < ! -i fn o tu s i n ga n yp r o f i l e> < d e p e n d e n c y > < g r o u p I d > o r g . j b o s s . a s < / g r o u p I d > < a r t i f a c t I d > j b o s s a s a r q u i l l i a n c o n t a i n e r m a n a g e d < / a r t i f a c t I d > < v e r s i o n > 7 . 2 . 0 . F i n a l < / v e r s i o n > < / d e p e n d e n c y >
Yu might want to check the poms included in the zip files ...
Now you are almost ready to run your first Arquillian test ( m v nc l e a nt e s t/ or using eclipse).
Embedded container
Using JBoss, all modes need a JBoss to be installed and localized by a r q u i l l i a n . x m l . We suggest the following approach: Make use of maven to build your archives and include the necessary dependencies within the POM. Whatever mode you might choose, put the relevant configuration into a decent profile. We have tested the managed and embedded option only.
< / p r o f i l e >
If you want to make an embedded test run from eclipse you have to add a system property or configure properly within the POM:
10
11
@ B e f o r e
p u b l i cv o i ds e t U p ( ){ f o o . s e t C r e a t i o n T i m e ( n e wD a t e ( S y s t e m . c u r r e n t T i m e M i l l i s ( ) ) ) ; f o o . s e t D e s c r i p t i o n ( " F o oB a r " ) ; f o o . s e t C r e a t i o n T i m e ( n e wD a t e ( S y s t e m . c u r r e n t T i m e M i l l i s ( ) ) ) ;
f o o=f o o S e r v i c e . c r e a t e F o o ( f o o ) ;
} @ T e s t p u b l i cv o i dt e s t F i n d A l l ( ){ L i s t < F o o >h i t s=f o o S e r v i c e . f i n d A l l F o o s ( ) ; A s s e r t . a s s e r t T r u e ( h i t s . s i z e ( )>0 ) ; }
2
@ A f t e r
p u b l i cv o i dt e a r D o w n ( ){ L i s t < F o o >h i t s=f o o S e r v i c e . f i n d A l l F o o s ( ) ; f o r( F o of o o:h i t s ){
f o o S e r v i c e . d e l e t e F o o ( f o o ) ;
} } }
Obviously this approach only works well for not-so-complicated objects and associations.
Put the script into the / s r c / t e s t / r e s o u r c e s / s c r i p t sfolder of your maven project and annotate the class accordingly:
13
@ R u n W i t h ( A r q u i l l i a n . c l a s s )
@ A p p l y S c r i p t B e f o r e ( " s c r i p t s / C r e a t e F o o . s q l " )
p u b l i cc l a s sF o o S e r v i c e A r q u i l l i a n S Q L S c r i p t T e s t{ @ E J B p r i v a t eF o o S e r v i c ef o o S e r v i c e ; @ D e p l o y m e n t p u b l i cs t a t i cA r c h i v e < ? >c r e a t e T e s t A r c h i v e ( ){ A r c h i v e < ? >a r c h i v e=A r c h i v e H e l p e r . g e t A r c h i v e ( ) ; r e t u r na r c h i v e ; } @ T e s t p u b l i cv o i dt e s t F i n d A l l ( ){ L i s t < F o o >h i t s=f o o S e r v i c e . f i n d A l l F o o s ( ) ; A s s e r t . a s s e r t T r u e ( h i t s . s i z e ( )>0 ) ; } @ T e s t p u b l i cv o i dt e s t F i n d F o o s E a r l i e r T h a n ( ){ D a t ef u t u r e=n e wD a t e ( S y s t e m . c u r r e n t T i m e M i l l i s ( )+1 0 0 0 0 0 ) ; L i s t < F o o >h i t s=f o o S e r v i c e . f i n d F o o s E a r l i e r T h a n ( f u t u r e ) ; A s s e r t . a s s e r t T r u e ( h i t s . s i z e ( )>0 ) ; } }
Everything should work fine now Obviously this model works fine for not-so-complicated objects and associations. If complex objects respective their associations exist, there might be better options.
@ U s i n g D a t a S e t ( " d a t a s e t s / F o o s . j s o n " )
Copyright and all intellectual property belongs to Brockhaus Group 14
p u b l i cc l a s sF o o S e r v i c e A r q u i l l i a n D a t a S e t T e s t{ @ E J B p r i v a t eF o o S e r v i c ef o o S e r v i c e ; @ D e p l o y m e n t p u b l i cs t a t i cA r c h i v e < ? >c r e a t e T e s t A r c h i v e ( ){ A r c h i v e < ? >a r c h i v e=A r c h i v e H e l p e r . g e t A r c h i v e ( ) ; r e t u r na r c h i v e ; } @ T e s t p u b l i cv o i dt e s t F i n d A l l ( ){ L i s t < F o o >h i t s=f o o S e r v i c e . f i n d A l l F o o s ( ) ; A s s e r t . a s s e r t T r u e ( h i t s . s i z e ( )>0 ) ; } @ T e s t p u b l i cv o i dt e s t F i n d F o o s E a r l i e r T h a n ( ){ D a t ef u t u r e=n e wD a t e ( S y s t e m . c u r r e n t T i m e M i l l i s ( )+1 0 0 0 0 0 ) ; L i s t < F o o >h i t s=f o o S e r v i c e . f i n d F o o s E a r l i e r T h a n ( f u t u r e ) ; A s s e r t . a s s e r t T r u e ( h i t s . s i z e ( )>0 ) ; } }
15
This class serves perfectly as long as you want to serialize just one foo, if you want to serialize more of them, you need a so-called wrapper class (note the field name of the collection, its a singular, leave it like this to get the expected result):
p u b l i cc l a s sF o o W r a p p e r{ L i s t < F o o >f o o=n e wA r r a y L i s t < F o o > ( ) ; p u b l i cL i s t < F o o >g e t F o o ( ){ r e t u r nf o o ; } p u b l i cv o i ds e t F o o ( L i s t < F o o >f o o ){ t h i s . f o o=f o o ; } }
Creating the JSON representation is simple like this (think of combining it with a findAll() method of the DAO layer):
p u b l i cc l a s sJ S O N P a r s e r T e s t{ p u b l i cs t a t i cv o i dm a i n ( S t r i n g [ ]a r g s ){ J S O N P a r s e r T e s tt e s t=n e wJ S O N P a r s e r T e s t ( ) ; t e s t . s e r i a l i z e F o o s ( ) ; } p r i v a t ev o i ds e r i a l i z e F o o s ( ){ F o o W r a p p e rw r a p p e r=n e wJ S O N P a r s e r T e s t . F o o W r a p p e r ( ) ; F o of o o 1=n e wF o o ( ) ; f o o 1 . s e t I d ( 9 9 8 l ) ; f o o 1 . s e t C r e a t i o n T i m e ( n e wD a t e ( S y s t e m . c u r r e n t T i m e M i l l i s ( ) ) ) ; f o o 1 . s e t D e s c r i p t i o n ( " F o oO n e " ) ;
16
F o of o o 2=n e wF o o ( ) ; f o o 2 . s e t I d ( 9 9 9 l ) ; f o o 2 . s e t C r e a t i o n T i m e ( n e wD a t e ( S y s t e m . c u r r e n t T i m e M i l l i s ( ) ) ) ; f o o 2 . s e t D e s c r i p t i o n ( " F o oT w o " ) ; w r a p p e r . g e t F o o ( ) . a d d ( f o o 1 ) ; w r a p p e r . g e t F o o ( ) . a d d ( f o o 2 ) ; S t r i n gj s o n=J S O N P a r s e r . g e t I n s t a n c e ( ) . t o J S O N ( w r a p p e r ) ; S y s t e m . o u t . p r i n t l n ( j s o n ) ; } p r i v a t ec l a s sF o o W r a p p e r{ L i s t < F o o >f o o=n e wA r r a y L i s t < F o o > ( ) ; p u b l i cL i s t < F o o >g e t F o o ( ){ r e t u r nf o o ; } p u b l i cv o i ds e t F o o ( L i s t < F o o >f o o ){ t h i s . f o o=f o o ; } } }
17