Test Java EE applications with Arquillian Ivan St. Ivanov
@ivan_stefanov About me @ivan_stefanov nosoftskills.com
@ivan_stefanov
@ivan_stefanov Java EE Changed a Lot  Standalone technologies ◦ EJB container ◦ JPA ◦ CDI  Arquillian testing framework
@ivan_stefanov Techniques to test Java EE apps  Testing Persistence  Testing Contexts and Dependency Injection (CDI)  Testing business logic  Testing whole scenarios
@ivan_stefanov The showcase app  Collects match predictions from registered users  Award points for correct predictions  Used technologies ◦ Java 8 ◦ Java EE 8 – JPA, CDI, EJB, JAX-RS, JSF  Source code: https://github.com/ivannov/predcomposer
@ivan_stefanov
@ivan_stefanov Testing Persistence  Use embedded databases (HSQLDB, Derby)  Covered by other tests, often not needed  Used for quick check of persistence code
@ivan_stefanov 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>
@ivan_stefanov 2) Initialize EntityManager protected static EntityManager entityManager; @BeforeClass public static void setupTestObjects() { EntityManagerFactory emf = Persistence .createEntityManagerFactory( "predcomposer-test"); entityManager = emf.createEntityManager(); }
@ivan_stefanov 3) Begin transaction @Before public void setUp() throws Exception { entityManager.getTransaction().begin(); insertTestData(); entityManager.flush(); this.competitionsService = new CompetitionsService(); competitionsService.entityManager = entityManager; }
@ivan_stefanov @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 test
@ivan_stefanov 5) Cleanup @After public void tearDown() { entityManager.getTransaction().rollback(); } @AfterClass public static void closeEntityManager() { entityManager.close(); }
@ivan_stefanov
@ivan_stefanov Testing CDI  Use CDI Unit or Deltaspike  Launches CDI container  Easy injection of dependencies, mocks, alternatives  Control of requests and sessions  Used for quick tests when dependencies and scopes are involved
@ivan_stefanov 1) Add dependency <dependency> <groupId>org.jglue.cdi-unit</groupId> <artifactId>cdi-unit</artifactId> <version>3.1.2</version> <scope>test</scope> </dependency>
@ivan_stefanov @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 test
@ivan_stefanov @Alternative public class PredictionsServiceAlternative extends PredictionsService { @Override public Set<Prediction> getPredictionsForGame(Game game) { // return two predictions } } 3) Create alternative
@ivan_stefanov @RunWith(CdiRunner.class) @ActivatedAlternatives({ PredictionsServiceAlternative.class, }) public class ViewGamePredictionsBeanTest { 4) Add the alternative
@ivan_stefanov
@ivan_stefanov Greeting earthlings
@ivan_stefanov Core principles  Tests should be portable to any container  Tests should be executable from both IDE and build tool  The platform should extend existing test frameworks
@ivan_stefanov Step 1 – pick a container  Container extensions ◦ JBoss, Tomcat, Weld, Glassfish, Jetty, WebSphere, WebLogic
@ivan_stefanov 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>
@ivan_stefanov Step 2 – connect the container  Container types ◦ Embedded ◦ Managed ◦ Remote
@ivan_stefanov 2) Configure container <arquillian> <container qualifier="arquillian-wildfly-managed"> <configuration> <property name="jbossHome"> target/wildfly-9.0.1.Final </property> </configuration> </container> </arquillian>
@ivan_stefanov Step 3 – package and deploy  ShrinkWrap library ◦ Deployment ◦ Resolve from Maven ◦ Create descriptors
@ivan_stefanov @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 archive
@ivan_stefanov Step 4 – run the test  Tests runs in-container ◦ CDI, EJB, JNDI available ◦ No need to mock most of the services  Present the result as a normal unit test
@ivan_stefanov @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 test
@ivan_stefanov @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 tests
@ivan_stefanov Step 5 – undeploy the test  Undeploy the test archive  Disconnect or stop the container
@ivan_stefanov
@ivan_stefanov That’s not all  Persistence extension  Warp  Drone  Graphene  AngularJS, Android, OSGi  …
@ivan_stefanov Graphene extension  Drive the application via page navigation  Support for AJAX  PageObject pattern
@ivan_stefanov 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>
@ivan_stefanov 2) Configure extension <arquillian> <extension qualifier="webdriver"> <property name="browser">phantomjs</property> </extension> </arquillian>
@ivan_stefanov 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(); } }
@ivan_stefanov 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); } }
@ivan_stefanov
@ivan_stefanov
@ivan_stefanov Resources  Showcase app https://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/

Testing Java EE apps with Arquillian

Editor's Notes

  • #4 Testing J2EE was considered hard