Test Java EE applications with Arquillian Ivan St

  • Slides: 42
Download presentation
Test Java EE applications with Arquillian Ivan St. Ivanov

Test Java EE applications with Arquillian Ivan St. Ivanov

About me @ivan_stefanov nosoftskills. com @ivan_stefanov

About me @ivan_stefanov nosoftskills. com @ivan_stefanov

@ivan_stefanov

@ivan_stefanov

Java EE Changed a Lot �Standalone technologies ◦ EJB container ◦ JPA ◦ CDI

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)

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

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

@ivan_stefanov

Testing Persistence �Use embedded databases (HSQLDB, Derby) �Covered by other tests, often not needed

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" transactiontype="RESOURCE_LOCAL"> <provider>org. hibernate. jpa. Hibernate.

1) Create persistence. xml <persistence version="2. 1"> <persistence-unit name="predcomposer-test" transactiontype="RESOURCE_LOCAL"> <provider>org. hibernate. jpa. Hibernate. Persistence. Provider</provider> <properties> <property name="javax. persistence. jdbc. driver“ value="org. hsqldb. jdbc. Driver"/> <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 Entity. Manager protected static Entity. Manager entity. Manager; @Before. Class public static

2) Initialize Entity. Manager protected static Entity. Manager entity. Manager; @Before. Class public static void setup. Test. Objects() { Entity. Manager. Factory emf = Persistence. create. Entity. Manager. Factory( "predcomposer-test"); entity. Manager = emf. create. Entity. Manager(); } @ivan_stefanov

3) Begin transaction @Before public void set. Up() throws Exception { entity. Manager. get.

3) Begin transaction @Before public void set. Up() throws Exception { entity. Manager. get. Transaction(). begin(); insert. Test. Data(); entity. Manager. flush(); this. competitions. Service = new Competitions. Service(); competitions. Service. entity. Manager = entity. Manager; } @ivan_stefanov

4) Write your test @Test public void should. Store. Competition() throws Exception { Competition

4) Write your test @Test public void should. Store. Competition() throws Exception { Competition new. Competition = new Competition( "Premiership 2015/2016", "The English Premier League"); Competition stored. Competition = competitions. Service. store. Competition(new. Competition); assert. Not. Null(stored. Competition. get. Id()); assert. Equals(new. Competition, entity. Manager. find(Competition. class, stored. Competition. get. Id())); } @ivan_stefanov

5) Cleanup @After public void tear. Down() { entity. Manager. get. Transaction(). rollback(); }

5) Cleanup @After public void tear. Down() { entity. Manager. get. Transaction(). rollback(); } @After. Class public static void close. Entity. Manager() { entity. Manager. close(); } @ivan_stefanov

@ivan_stefanov

@ivan_stefanov

Testing CDI �Use CDI Unit or Deltaspike �Launches CDI container �Easy injection of dependencies,

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> <group. Id>org. jglue. cdi-unit</group. Id> <artifact. Id>cdi-unit</artifact. Id> <version>3. 1.

1) Add dependency <dependency> <group. Id>org. jglue. cdi-unit</group. Id> <artifact. Id>cdi-unit</artifact. Id> <version>3. 1. 2</version> <scope>test</scope> </dependency> @ivan_stefanov

2) Write the test @Run. With(Cdi. Runner. class) public class View. Game. Predictions. Bean.

2) Write the test @Run. With(Cdi. Runner. class) public class View. Game. Predictions. Bean. Test { @Inject private View. Game. Predictions. Bean bean; @Test public void should. Load. Game. Predictions. Upon. Request() { bean. show. Game. Predictions(game 2); assert. Equals(2, bean. get. Predictions(). size()); } } @ivan_stefanov

3) Create alternative @Alternative public class Predictions. Service. Alternative extends Predictions. Service { @Override

3) Create alternative @Alternative public class Predictions. Service. Alternative extends Predictions. Service { @Override public Set<Prediction> get. Predictions. For. Game(Game game) { // return two predictions } } @ivan_stefanov

4) Add the alternative @Run. With(Cdi. Runner. class) @Activated. Alternatives({ Predictions. Service. Alternative. class,

4) Add the alternative @Run. With(Cdi. Runner. class) @Activated. Alternatives({ Predictions. Service. Alternative. class, }) public class View. Game. Predictions. Bean. Test { @ivan_stefanov

@ivan_stefanov

@ivan_stefanov

Greeting earthlings @ivan_stefanov

Greeting earthlings @ivan_stefanov

Core principles �Tests should be portable to any container �Tests should be executable from

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,

Step 1 – pick a container �Container extensions ◦ JBoss, Tomcat, Weld, Glassfish, Jetty, Web. Sphere, Web. Logic @ivan_stefanov

1) Add dependencies and profile <dependency> <group. Id>org. jboss. arquillian. junit</group. Id> <artifact. Id>arquillian-junit-container</artifact.

1) Add dependencies and profile <dependency> <group. Id>org. jboss. arquillian. junit</group. Id> <artifact. Id>arquillian-junit-container</artifact. Id> <scope>test</scope> </dependency> <group. Id>org. wildfly</group. Id> <artifact. Id> wildfly-arquillian-container-managed </artifact. Id> <scope>test</scope> </dependency> @ivan_stefanov

Step 2 – connect the container �Container types ◦ Embedded ◦ Managed ◦ Remote

Step 2 – connect the container �Container types ◦ Embedded ◦ Managed ◦ Remote @ivan_stefanov

2) Configure container <arquillian> <container qualifier="arquillian-wildfly-managed"> <configuration> <property name="jboss. Home"> target/wildfly-9. 0. 1. Final

2) Configure container <arquillian> <container qualifier="arquillian-wildfly-managed"> <configuration> <property name="jboss. Home"> target/wildfly-9. 0. 1. Final </property> </configuration> </container> </arquillian> @ivan_stefanov

Step 3 – package and deploy �Shrink. Wrap library ◦ Deployment ◦ Resolve from

Step 3 – package and deploy �Shrink. Wrap library ◦ Deployment ◦ Resolve from Maven ◦ Create descriptors @ivan_stefanov

3) Prepare the test archive @Run. With(Arquillian. class) public class Competitions. Service. Integration. Test

3) Prepare the test archive @Run. With(Arquillian. class) public class Competitions. Service. Integration. Test { @Deployment public static Web. Archive create. Deployment() { return Shrink. Wrap. create(Web. Archive. class). add. Class(Competitions. Service. class). add. Package(Prediction. class. get. Package()). add. As. Resource( new File("src/main/resources/META-INF/persistence. xml"), "META-INF/persistence. xml"); } } @ivan_stefanov

Step 4 – run the test �Tests runs in-container ◦ CDI, EJB, JNDI available

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

4. 1) Write the test @Inject private Competitions. Service competitions. Service; @Test public void

4. 1) Write the test @Inject private Competitions. Service competitions. Service; @Test public void should. Create. Competition() throws Exception { test. Competition = new Competition("Premiership 2015/2016", "English Premier League"); test. Game = new Game("Manchester City", "Juventus", Local. Date. Time. of(2015, 9, 15, 21, 45)); test. Competition. get. Games(). add(test. Game); Competition persisted. Competition = competitions. Service. store. Competition(test. Competition); assert. Not. Null(persisted. Competition. get. Id()); assert. Equals(test. Competition, persisted. Competition); } @ivan_stefanov

4. 2) Client side tests @Run. With(Arquillian. class) @Run. As. Client public class Competition.

4. 2) Client side tests @Run. With(Arquillian. class) @Run. As. Client public class Competition. Resource. Test { @Test public void should. Create. Competition(@Arquillian. Resource URL base) { URL url = new URL(base, "rest/competition"); Web. Target target = Client. Builder. new. Client(). target(url. to. External. Form()); Form new. Competition. Form = new Form(); new. Competition. Form. param("name", COMPETITION_NAME); new. Competition. Form. param("description", DESCRIPTION); Response response = target. request(Media. Type. APPLICATION_JSON_TYPE). post(Entity. entity(new. Competition. Form, Media. Type. APPLICATION_FORM_URLENCODED_TYPE)); assert. Equals(201, response. get. Status()); } } @ivan_stefanov

Step 5 – undeploy the test �Undeploy the test archive �Disconnect or stop the

Step 5 – undeploy the test �Undeploy the test archive �Disconnect or stop the container @ivan_stefanov

@ivan_stefanov

@ivan_stefanov

That’s not all �Persistence extension �Warp �Drone �Graphene �Angular. JS, Android, OSGi �… @ivan_stefanov

That’s not all �Persistence extension �Warp �Drone �Graphene �Angular. JS, Android, OSGi �… @ivan_stefanov

Graphene extension �Drive the application via page navigation �Support for AJAX �Page. Object pattern

Graphene extension �Drive the application via page navigation �Support for AJAX �Page. Object pattern @ivan_stefanov

1) Add dependencies <dependency> <group. Id>org. jboss. arquillian. extension</group. Id> <artifact. Id>arquillian-drone-bom</artifact. Id> <type>pom</type>

1) Add dependencies <dependency> <group. Id>org. jboss. arquillian. extension</group. Id> <artifact. Id>arquillian-drone-bom</artifact. Id> <type>pom</type> <scope>import</scope> </dependency> <group. Id>org. jboss. arquillian. selenium</group. Id> <artifact. Id>selenium-bom</artifact. Id> <type>pom</type> <scope>import</scope> </dependency> <group. Id>org. jboss. arquillian. graphene</group. Id> <artifact. Id>graphene-webdriver</artifact. Id> <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

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 Login. Page { @Find. By(id

3) Create the page object @Location("login. jsf") public class Login. Page { @Find. By(id = "login. Form: user. Name") private Web. Element user. Name; @Find. By(id = "login. Form: password") private Web. Element password; @Find. By(id = "login. Form: login") private Web. Element login. Button; public void login(String user. Name, String password) { this. user. Name. send. Keys(user. Name); this. password. send. Keys(password); guard. Http(login. Button). click(); } } @ivan_stefanov

4) Create the scenario test @Run. With(Arquillian. class) @Run. As. Client public class Login.

4) Create the scenario test @Run. With(Arquillian. class) @Run. As. Client public class Login. Scenario. Test { @Drone private Web. Driver browser; @Page private Home. Page home. Page; @Test public void should. Say. Hello. Upon. Successful. Login( @Initial. Page Login. Page login. Page) { login. Page. login("ivan", "ivan"); home. Page. assert. Greeting. Message("Ivan"); home. Page. assert. Game. Form. Visible(true); } } @ivan_stefanov

@ivan_stefanov

@ivan_stefanov

@ivan_stefanov

@ivan_stefanov

Resources � Showcase app https: //github. com/ivannov/predcomposer �Arquillian http: //aslakknutsen. github. io/presentations/ https: //rpestano.

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/ @ivan_stefanov