Test Java EE applications with Arquillian Ivan St. Ivanov
@ivan_stefanov About nosoftskills.com
@ivan_stefanov
“ The purpose of automated testing is to enable change. Verifying correctness is just a nice side effect. - Jeremy Norris
@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:
@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 org.hibernate.jpa.HibernatePersistenceProvider
@ivan_stefanov 2) Initialize EntityManager protected static EntityManager public static void setupTestObjects() { EntityManagerFactory emf = Persistence.createEntityManagerFactory( "predcomposer-test"); entityManager = emf.createEntityManager(); }
@ivan_stefanov 3) Begin public void setUp() throws Exception { entityManager.getTransaction().begin(); insertTestData(); entityManager.flush(); this.competitionsService = new CompetitionsService(); competitionsService.entityManager = entityManager; }
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) public void tearDown() { entityManager.getTransaction().rollback(); public static void closeEntityManager() { entityManager.close(); }
@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 org.jglue.cdi-unit cdi-unit test
public class ViewGamePredictionsBeanTest private ViewGamePredictionsBean public void shouldLoadGamePredictionsUponRequest() { bean.showGamePredictions(game2); assertEquals(2, bean.getPredictions().size()); } } 2) Write the test
public class PredictionsServiceAlternative extends PredictionsService public Set getPredictionsForGame(Game game) { // return two predictions } 3) Create alternative
@ivan_stefanov PredictionsServiceAlternative.class, }) public class ViewGamePredictionsBeanTest { 4) Add the alternative
@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 org.jboss.arquillian.junit arquillian-junit-container test org.wildfly wildfly-arquillian-container-managed test
@ivan_stefanov Step 2 – connect the container Container types ◦ Embedded ◦ Managed ◦ Remote
@ivan_stefanov 2) Configure container target/wildfly Final
@ivan_stefanov Step 3 – package and deploy ShrinkWrap library ◦ Deployment ◦ Resolve from Maven ◦ Create descriptors
public class CompetitionsServiceIntegrationTest 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
private CompetitionsService 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 public class CompetitionResourceTest public void 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
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 org.jboss.arquillian.extension arquillian-drone-bom pom import org.jboss.arquillian.selenium selenium-bom pom import org.jboss.arquillian.graphene graphene-webdriver pom test
@ivan_stefanov 2) Configure extension phantomjs
@ivan_stefanov 3) Create the page public class LoginPage = "loginForm:userName") private WebElement = "loginForm:password") private WebElement = "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 public class LoginScenarioTest private WebDriver private HomePage public void LoginPage loginPage) { loginPage.login("ivan", "ivan"); homePage.assertGreetingMessage("Ivan"); homePage.assertGameFormVisible(true); } }
@ivan_stefanov
Resources Showcase app Arquillian mocks/