Arquillian Ivan St Ivanov About me ivanstefanov nosoftskillscom The purpose of automated testing is to enable change Verifying correctness is just a nice side effect Jeremy ID: 617525
Download Presentation The PPT/PDF document "Test Java EE applications with" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Test Java EE applications with Arquillian
Ivan St. IvanovSlide2
About me
@
ivan_stefanov
nosoftskills.comSlide3Slide4
“
The purpose of automated testing is to enable change. Verifying correctness is just a nice side effect.
-
Jeremy
NorrisSlide5
Java EE Changed a Lot
Standalone technologiesEJB containerJPACDI
Arquillian testing frameworkSlide6
Techniques to test Java EE apps
Testing PersistenceTesting Contexts and Dependency Injection (CDI)Testing business logicTesting whole scenariosSlide7
The showcase app
Collects match predictions from registered usersAward points for correct predictionsUsed technologies
Java 8Java EE 8 – JPA, CDI, EJB, JAX-RS, JSFSource code:https://github.com/ivannov/predcomposer Slide8Slide9
Testing Persistence
Use embedded databases (HSQLDB, Derby)Covered by other tests, often not neededUsed for quick check of persistence codeSlide10
1) Create persistence.xml
<
persistence
version
="2.1"
>
<
persistence-unit
name
="
predcomposer
-test"
transaction-type
="RESOURCE_LOCAL"
>
<
provider
>
org.hibernate.jpa.HibernatePersistenceProvider
</
provider
>
<
properties
>
<
property
name
="
javax.persistence.jdbc.driver
“
value
="
org.hsqldb.jdbcDriver
"
/>
<
property
name
="javax.persistence.jdbc.url“
value
="
jdbc:hsqldb:mem:testdb
"
/>
<
property
name
="
javax.persistence.jdbc.user
"
value
="
sa
"
/>
<
property
name
="
javax.persistence.jdbc.password
"
value
=""
/>
</
properties
>
</
persistence-unit
>
</
persistence
>Slide11
2) Initialize
EntityManager
protected static
EntityManager
entityManager
;
@
BeforeClass
public static void
setupTestObjects
() {
EntityManagerFactory
emf
= Persistence
.
createEntityManagerFactory
(
"
predcomposer
-test"
);
entityManager
=
emf.createEntityManager
();
}Slide12
3) Begin transaction
@Before
public void
setUp
()
throws
Exception {
entityManager
.getTransaction
().begin
();
insertTestData
();
entityManager
.flush
();
this
.
competitionsService
=
new
CompetitionsService
();
competitionsService
.
entityManager
=
entityManager
;
}Slide13
@Test
public void
shouldStoreCompetition
()
throws
Exception {
Competition
newCompetition
=
new
Competition(
"Premiership 2015/2016"
,
"The English Premier League"
);
Competition
storedCompetition
=
competitionsService
.storeCompetition(newCompetition); assertNotNull(storedCompetition.getId()); assertEquals(newCompetition, entityManager.find(Competition.class, storedCompetition.getId()));}
4) Write your testSlide14
5) Cleanup
@After
public void
tearDown
() {
entityManager
.getTransaction
().rollback();
}
@
AfterClass
public static void
closeEntityManager
() {
entityManager
.close
();
}Slide15Slide16
Testing CDI
Use CDI Unit or DeltaspikeLaunches CDI containerEasy injection of dependencies, mocks, alternatives
Control of requests and sessionsUsed for quick tests when dependencies and scopes are involvedSlide17
1) Add dependency
<
dependency
>
<
groupId
>
org.jglue.cdi
-unit</
groupId
>
<
artifactId
>cdi-unit</
artifactId
>
<
version
>3.1.2</
version
> <scope>test</scope></dependency>Slide18
@
RunWith
(
CdiRunner.
class
)
public class
ViewGamePredictionsBeanTest
{
@Inject
private
ViewGamePredictionsBean
bean
;
@Test
public void shouldLoadGamePredictionsUponRequest() { bean.showGamePredictions(game2); assertEquals(2, bean.getPredictions().size()); }}2) Write the testSlide19
@Alternative
public class
PredictionsServiceAlternative
extends
PredictionsService
{
@
Override
public
Set<Prediction>
getPredictionsForGame
(Game game) {
// return two
predictions
}
}3) Create alternativeSlide20
@
RunWith
(
CdiRunner.
class
)
@
ActivatedAlternatives
({
PredictionsServiceAlternative.
class
,
})
public class
ViewGamePredictionsBeanTest
{
4
)
Add
the alternativeSlide21Slide22
Greeting earthlingsSlide23
Core principles
Tests should be portable to any containerTests should be executable from both IDE and build toolThe platform should extend existing test frameworksSlide24
Step 1 – pick a container
Container extensionsJBoss, Tomcat, Weld, Glassfish, Jetty, WebSphere,
WebLogicSlide25
1) Add dependencies and profile
<
dependency
>
<
groupId
>
org.jboss.arquillian.junit
</
groupId
>
<
artifactId
>
arquillian
-
junit
-container</
artifactId
>
<scope>test</scope></dependency><dependency> <groupId>org.wildfly</groupId> <artifactId> wildfly-arquillian-container-managed </
artifactId
>
<
scope
>test</
scope
>
</
dependency
>Slide26
Step 2 – connect the container
Container typesEmbedded Managed
RemoteSlide27
2) Configure container
<
arquillian
>
<
container
qualifier
="
arquillian
-
wildfly
-managed"
>
<
configuration
>
<
property
name
="
jbossHome"> target/wildfly-9.0.1.Final </property> </configuration> </container> </arquillian>Slide28
Step 3 – package and deploy
ShrinkWrap libraryDeployment
Resolve from MavenCreate descriptorsSlide29
@
RunWith
(
Arquillian.
class
)
public class
CompetitionsServiceIntegrationTest
{
@Deployment
public static
WebArchive
createDeployment
() {
return
ShrinkWrap.create(WebArchive.class) .addClass(CompetitionsService.class) .addPackage(Prediction.class.getPackage()) .addAsResource( new File("src/main/resources/META-INF/persistence.xml"),
"META-INF/persistence.xml"
);
}
}
3) Prepare the test archiveSlide30
Step 4 – run the test
Tests runs in-containerCDI, EJB, JNDI available
No need to mock most of the servicesPresent the result as a normal unit testSlide31
@Inject
private
CompetitionsService
competitionsService
;
@Test
public
void
shouldCreateCompetition
()
throws
Exception {
testCompetition
= new Competition("Premiership 2015/2016", "English Premier League"); testGame = new Game("Manchester City", "Juventus", LocalDateTime.of(2015, 9, 15, 21,
45
));
testCompetition
.getGames
().add(
testGame
);
Competition
persistedCompetition
=
competitionsService
.storeCompetition
(
testCompetition
);
assertNotNull
(
persistedCompetition.getId
());
assertEquals
(
testCompetition
,
persistedCompetition
);
}
4.1) Write the testSlide32
@
RunWith
(
Arquillian.
class
)
@
RunAsClient
public class
CompetitionResourceTest
{
@Test
public void
shouldCreateCompetition
(
@
ArquillianResource
URL base) { URL url = new URL(base, "rest/competition"); WebTarget target = ClientBuilder.newClient().target(url.toExternalForm()); Form newCompetitionForm = new Form(); newCompetitionForm.param("name", COMPETITION_NAME); newCompetitionForm.param
(
"description"
,
DESCRIPTION
);
Response
response
=
target.request
(
MediaType.
APPLICATION_JSON_TYPE
)
.
post(
Entity.
entity
(
newCompetitionForm
,
MediaType.
APPLICATION_FORM_URLENCODED_TYPE
));
assertEquals
(
201
,
response.getStatus
());
}
}
4.2) Client side testsSlide33
Step 5 –
undeploy
the testUndeploy the test archive
Disconnect or stop the containerSlide34Slide35
That’s not all
Persistence extensionWarpDroneGraphene
AngularJS, Android, OSGi…Slide36
Graphene
extensionDrive the application via page navigation
Support for AJAXPageObject patternSlide37
1) Add dependencies
<
dependency
>
<
groupId
>
org.jboss.arquillian.extension
</
groupId
>
<
artifactId
>
arquillian
-drone-
bom
</
artifactId
>
<type>pom</type> <scope>import</scope></dependency><dependency> <groupId>org.jboss.arquillian.selenium</groupId> <artifactId>selenium-bom</
artifactId
>
<
type
>
pom
</
type
>
<
scope
>import</
scope
>
</
dependency
>
<
dependency
>
<
groupId
>
org.jboss.arquillian.graphene
</
groupId
>
<
artifactId
>
graphene-webdriver
</
artifactId
>
<
type
>
pom
</
type
>
<
scope
>test</
scope
>
</
dependency
>Slide38
2) Configure extension
<
arquillian
>
<
extension
qualifier
="
webdriver
"
>
<
property
name
="browser"
>
phantomjs
</
property
>
</extension></arquillian>Slide39
3) Create the page object
@Location
(
"
login.jsf
"
)
public class
LoginPage
{
@
FindBy
(id =
"
loginForm:userName
"
)
private
WebElement userName; @FindBy(id = "loginForm:password") private WebElement password; @FindBy(id = "loginForm:login")
private
WebElement
loginButton
;
public void
login(String
userName
, String password) {
this
.
userName
.sendKeys
(
userName
);
this
.
password
.sendKeys
(password);
guardHttp
(
loginButton
).click();
}
}Slide40
4) Create the scenario test
@
RunWith
(
Arquillian.
class
)
@
RunAsClient
public class
LoginScenarioTest
{
@Drone
private
WebDriver
browser
; @Page private HomePage homePage; @Test public void shouldSayHelloUponSuccessfulLogin( @InitialPage LoginPage loginPage) { loginPage.login
(
"
ivan
"
,
"
ivan
"
);
homePage
.assertGreetingMessage
(
"Ivan"
);
homePage
.assertGameFormVisible
(
true
);
}
}Slide41Slide42Slide43
Resources
Showcase apphttps://github.com/ivannov/predcomposer Arquillian
http://aslakknutsen.github.io/presentations/https://rpestano.wordpress.com/2014/06/08/arquillian/
https://rpestano.wordpress.com/2014/10/25/arquillian-and-mocks/