
When it comes to JavaEE, the biggest obstacle is conducting test, especially for EJB. This makes EJB is drawback for most developers. In fact EJB offer several enterprise features for business logic implementation such as remote call, security, transaction, etc. So, it will be waste to give up those benefits. Fortunately, Java EE provides testing framework like Arquillian for conducting the test. In this post, we will demonstrate how to perform enterprise business component by using Arquillian .
Table Content
In this post, we arrange as below section
- Overview on Arquillian
- Create Java Enterprise Project
- Setup Test Environment with Arquillian
- Test CID Project
- Test EJB Project
- Test JPA Project
- Reference
About Arquillian provides Java EE environment to the business objects (such as JPA, EJB, WAR, etc.). Arquillian takes care of building and shutdown environment, then run your test case as seperate client. Wildfly swarm provides wildfly application server wrapped around to an application to support application execution in single archive as jar file. By combining Arquillian and Wildfly Swarm we will demoinstrate how to create and run test for Java EE application as following.
But before we start, we would like to go a bit detail about Arquillian and Wildfly Swarm. First, We will discuss a bit detail about Arquillian, it is testing integration tools.
1. Overview on Arquillian
Let's start with looking at overall on Arquillian. Arquillian allows developers create their own test unit for enterprise application components, it leverages existing Java EE container to execute Jave Enterprise Businsess components like EJB, CDI, JMS, JPA. Arquillian provides test runner for Junit to the business component, it delegates test execution to service provider such as Wildfly, Glassfish, Tomcat, etc.
![]() |
Fig 02 Arquillian Architecture |
Arquillian can be integrated with Eclipse and Maven seamlessly without any configuration required. Shrinkwrap dispatch test cases to container's environment. Arquillian packed all the test packages to the ShrinkWrap-defined archive at runtime and deployed to the container. After testing is completed Arquillian undeployed the archive.
2. Create Jave Enterprise Projects
Now before we could start testing Java EE component, we need to create Java EE project that included JPA project, EJB project, Web Project.
First, we create JPA project to provide access to databases. For our environment, we have use PostgreSQL 12 for backend database. In our database, we have create as following scheme and create records as below SQL script.
CREATE TABLE IF NOT EXISTS booktbl
(
sid varchar primary key,
title varchar not null,
author varchar not null
);
INSERT INTO booktbl (sid,title,author) VALUES
('0001','book01','author01'),
('0002','book02','author02'),
('0003','book03','author03'),
('0004','book04','author04'),
('0005','book05','author05'),
('0006','book06','author06'),
('0007','book07','author07'),
('0008','book08','author08'),
('0009','book09','author09'),
('0010','book10','author10');
2.1 Create JPA Project
After we create SQL scheme for testing, we start create JPA project to map table to the java object. After creating project, we need to create Entity class to map with the database's table and the persistence.xml should look like below.
Fig 03 Create JPA Project |
After createing Book class, we should have as following.
package pro.tikkwiki.ee.arq.jpa.entity;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the booktbl database table.
*
*/
@Entity
@Table(name="booktbl")
@NamedQuery(name="Book.findAll", query="SELECT b FROM Book b")
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private String sid;
private String author;
private String title;
public Book() {
}
public String getSid() {
return this.sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getAuthor() {
return this.author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
}
For persistence.xml should be as following.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="java-ee-08-web" transaction-type="JTA">
<jta-data-source>java:/sampledbs</jta-data-source>
<properties>
<!-- Properties for Hibernate -->
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
2.2 Create EJB Project
Second, we create EJB project to implement business component.
After creating EJB project, we need to import JPA project into EJB that we have created.
Then We create interface for BookDaoLocal as below.
package pro.tikkwiki.ee.arq.ejb.dao;
import java.util.List;
import javax.ejb.Local;
import pro.tikkwiki.ee.arq.jpa.entity.Book;
@Local
public interface BookDaoLocal {
public List<Book> getAllBooks();
}
Then we create BookDaoImp class that implement the interface.
package pro.tikkwiki.ee.arq.ejb.dao;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import pro.tikkwiki.ee.arq.jpa.entity.Book;
/**
* Session Bean implementation class BookDaoImp
*/
@Stateless(mappedName = "bookDao")
@LocalBean
public class BookDaoImp implements BookDaoLocal {
@PersistenceContext
private EntityManager em;
/**
* Default constructor.
*/
public BookDaoImp() {
super();
}
@Override
public List<Book> getAllBooks() {
TypedQuery<Book> query = em.createNamedQuery("Book.findAll", Book.class);
return query.getResultList();
}
}
And one more bean to just create a simple EJB
package pro.tikkwiki.ee.arq.ejb.dao;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
/**
* Session Bean implementation class CustomEJB
*/
@Stateless
@LocalBean
public class CustomEJB {
/**
* Default constructor.
*/
public CustomEJB() {
super();
}
public String doSomething() {
return "Do Someting by EJB";
}
}
2.3 Create Dynamic Web Project
Now we create dynamic web project (by maven project ) and include all project such as JPA, EJB into Web Dynamic project.
In the dynamic web project, we create our test case here. For our web.xml, we created as below.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>Servlet 3.0 Web Application</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>com.sun.faces.enableRestoreView11Compatibility</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.allowTextChildren</param-name>
<param-value>true</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
</web-app>
For pom.xml, we create as following
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pro.itstikk</groupId>
<artifactId>java-ee-08-web</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>java-ee-08-web Maven Webapp</name>
<url>http://blog.tikkwiki.pro</url>
<description>A starter Java EE 8 webapp project for use on WildFly 10</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- JBoss dependency versions -->
<version.wildfly.maven.plugin>1.0.2.Final</version.wildfly.maven.plugin>
<!-- Define the version of the JBoss BOMs we want to import to specify tested
stacks. -->
<version.jboss.bom>10.1.0.Final</version.jboss.bom>
<!-- other plug-in versions -->
<version.war.plugin>3.0.0</version.war.plugin>
<!-- maven-compiler-plugin -->
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.wildfly.bom</groupId>
<artifactId>wildfly-javaee7-with-tools</artifactId>
<version>${version.jboss.bom}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- First declare the APIs we depend on and need for compilation. All of
them are provided by WildFly -->
<!-- Import the CDI API, we use provided scope as the API is included in
WildFly -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Import the Common Annotations API (JSR-250), we use provided scope
as the API is included in WildFly -->
<dependency>
<groupId>org.jboss.spec.javax.annotation</groupId>
<artifactId>jboss-annotations-api_1.2_spec</artifactId>
<scope>provided</scope>
</dependency>
<!-- Import the JPA API, we use provided scope as the API is included in
WildFly -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Import the EJB API, we use provided scope as the API is included in
WildFly -->
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
<scope>provided</scope>
</dependency>
<!-- Import the JSF API, we use provided scope as the API is included in
WildFly -->
<dependency>
<groupId>org.jboss.spec.javax.faces</groupId>
<artifactId>jboss-jsf-api_2.2_spec</artifactId>
<scope>provided</scope>
</dependency>
<!-- Needed for running tests (you may also use TestNG) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- Optional, but highly recommended -->
<!-- Arquillian allows you to test enterprise code such as EJBs and Transactional(JTA)
JPA from JUnit/TestNG -->
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.protocol</groupId>
<artifactId>arquillian-protocol-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>java-ee-08-web</finalName>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${version.war.plugin}</version>
<configuration>
<!-- Java EE doesn't require web.xml, Maven needs to catch up! -->
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- The WildFly plug-in deploys the WAR to a local WildFly container -->
<!-- To use, run: mvn package wildfly:deploy -->
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>${version.wildfly.maven.plugin}</version>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<!-- An optional Arquillian testing profile that executes tests in your
WildFly instance -->
<!-- This profile will start a new WildFly instance, and execute the test,
shutting it down when done -->
<!-- Run with: mvn clean test -Parq-wildfly-managed -->
<id>arq-wildfly-managed</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-container-managed</artifactId>
<version>2.0.1.Final</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
<profile>
<!-- An optional Arquillian testing profile that executes tests in a remote
WildFly instance -->
<!-- Run with: mvn clean test -Parq-wildfly-remote -->
<id>arq-wildfly-remote</id>
<dependencies>
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-container-remote</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
3.Setup Environment Arquillian
Now is to setup testing environment for creating test case unit and deploying test unit to the container. In the dynamic web project, we need to create arquillian.xml to specify our container that we will use to deploy test package.
Fig 06 create test environment |
Below is how arquillian.xml looks like.
<?xml version="1.0" encoding="UTF-8"?>
<!--
JBoss, Home of Professional Open Source
Copyright 2015, Red Hat, Inc. and/or its affiliates, and individual
contributors by the @authors tag. See the copyright.txt in the
distribution for a full listing of individual contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<!-- Force the use of the Servlet 3.0 protocol with all containers, as it is the most mature -->
<defaultProtocol type="Servlet 3.0" />
<!-- Example configuration for a remote WildFly instance -->
<container qualifier="wildfly" default="true">
<!-- By default, arquillian will use the JBOSS_HOME environment variable. Alternatively, the configuration below can be uncommented. -->
<configuration>
<property name="jbossHome">D:/Devs/wildfly-10.1.0.Final</property>
<property name="allowConnectingToRunningServer">true</property>
</configuration>
</container>
</arquillian>
In order to test CDI, we also need to create beans.xml inside the project. beans.xml is just an emplty xml file as shown below.
<?xml version="1.0" encoding="UTF-8"?>
After creating arquillian.xml then we are ready to test.
4. Testing CDI Project
In order to test CDI, we just create any bean in dynamic web project.Honestly, CDI testing is quite straigth forward. We just create java bean as below.
package pro.itstikk.bean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Named;
@Named
public class CustomBean {
private static Logger logger = Logger.getLogger(CustomBean.class.getName());
public void doSomething() {
logger.log(Level.INFO,"Call Do Something");
}
}
Then, we create our test unit for CustomBean.java as below
package pro.itstikk.test;
import javax.inject.Inject;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import pro.itstikk.bean.CustomBean;
@RunWith(Arquillian.class)
public class ApplicationUnitTestCDI {
@Deployment
public static Archive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "ApplicationUntitTest.war")
.addClass(CustomBean.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
@Inject
private CustomBean bean;
@Test
public void test01() {
bean.doSomething();
Assert.assertTrue(true);
}
}
Then, we need to start execute test case and we should get the response as following.
Test Result should be as below
5. Test EJB Project
Next is to conduct testing for EJB in the EJB project. To test EJB we just need to create test unit as following.
package pro.itstikk.test;
import javax.ejb.EJB;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import pro.tikkwiki.ee.arq.ejb.dao.CustomEJB;
@RunWith(Arquillian.class)
public class ApplicationUnitTestEJB {
@Deployment
public static Archive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "ApplicationUntitTestEJB.war")
.addClass(CustomEJB.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
@EJB
private CustomEJB customEJB;
@Test
public void test() {
Assert.assertNotNull(customEJB.doSomething());
}
}
Once we execute test unit, we shall get below result as return.
And our test result shall be
6. Testing JPA Project
Finally, we test JPA by create below test unit
package pro.itstikk.test;
import javax.ejb.EJB;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import pro.tikkwiki.ee.arq.ejb.dao.BookDaoEJB;
import pro.tikkwiki.ee.arq.ejb.dao.BookDaoImp;
import pro.tikkwiki.ee.arq.ejb.dao.BookDaoLocal;
import pro.tikkwiki.ee.arq.jpa.entity.Book;
@RunWith(Arquillian.class)
public class ApplicationUnitTestJPA {
@Deployment
public static Archive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "ApplicationUntitJPA.war")
.addPackage(BookDaoEJB.class.getPackage())
.addPackage(BookDaoLocal.class.getPackage())
.addPackage(BookDaoImp.class.getPackage())
.addPackage(Book.class.getPackage())
.addAsResource("META-INF/persistence.xml")
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
@EJB
private BookDaoEJB bookDao;
@EJB
private BookDaoLocal bookDaoLocal;
@Test
public void test01() {
Assert.assertNotNull(bookDao.getAllBooks());
}
@Test
public void test02() {
Assert.assertNotNull(bookDaoLocal.getAllBooks());
}
}
And the result shall be as below
No comments:
Post a Comment