Quantcast
Channel: Java Team at Kentor » Frameworks
Viewing all articles
Browse latest Browse all 26

Creating a JPA layer using Java EE 6

$
0
0

Go back to Index

This session is a follow up on tdd-development-with-EJB

The scope of the session is to add a database layer and some CRUD methods.
This will be a simple solution using JPA and Arquillian.

We are going to convert our Order.java and Product.java to @Entity which are going to map to a database table. In order to make them work with the database we will rename the files to a more appropriate name, OrderEntity and ProductEntity
We are also going to make some configuration changes so that we can support testing JPA on different containers. In this example we will configure jbossas-managed and glassfish-embedded.
Let us start with some configurations.
1. glassfish-embedded
under the folder “src/test/resources” create a new source folder called glassfish-embedded, in that folder we will create 3 files
test-persistence.xml
glassfish-resources.xml
logging.properties
We also need to create a file called arquillian.xml one level up at “src/test/resources”

In order to to get JPA to work we need to have a persistence.xml file, we will create one of these for each container (called test-persistence.xml) and we will have Arquillian copy it in to the deploy package as persistence.xml at runtime.
For the glassfish-embedded container we will use JTA datasource and eclipse-link together with a derby in memory database
Lets start by editing the test-persistence.xml, the contentes of the file should look like this,

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="

http://java.sun.com/xml/ns/persistence

        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="pu">
        <jta-data-source>jdbc/arquillian</jta-data-source>
        <properties>
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
            <property name="eclipselink.logging.level.sql" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Now we need to create the datasource, so open the glassfish-resources.xml and add the following

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC
    "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN"
    "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <jdbc-resource pool-name="ArquillianEmbeddedDerbyPool"
        jndi-name="jdbc/arquillian"/>
    <jdbc-connection-pool name="ArquillianEmbeddedDerbyPool"
        res-type="javax.sql.DataSource"
        datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource"
        is-isolation-level-guaranteed="false">
        <property name="databaseName" value="target/databases/derby"/>
        <property name="createDatabase" value="create"/>
    </jdbc-connection-pool>
</resources>

I could have put these configurations in one file, but i wanted to limit the use of different configurations as much as possible.
Next we need to setup logging, so open the logging.properties and add the following

handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%4$s: %5$s%n
java.util.logging.ConsoleHandler.level=FINEST

open the arquillian.xml file and tell it where the glassfish-resources.xml file is located, we will do this for the specific container.

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <container qualifier="glassfish-embedded" default="true">
        <configuration>
            <property name="resourcesXml">
                src/test/resources-glassfish-embedded/glassfish-resources.xml
            </property>
        </configuration>
    </container>
</arquillian>

Depending on how your system is set up, you might need to create a derby.log file in the root of your project. Otherwise the application will create it for you at runtime.

2. Before we continue we will configure the project to use jboss as well, this is so you can choose to use either of them or both even before you start coding.
We configured glassfish to use in memory derby database and we will configure jboss to use H2 in memory database and in a future post we will look at using both MySQL and MongoDB.

As we did with the glassfish configuration we need to add a new source folder called “jbossas-managed” under “src/test/resources”
In there we will create one file called, “test-persistence.xml” and it should look like something like this.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="

http://java.sun.com/xml/ns/persistence

        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="pu">
        <jta-data-source>jdbc/arquillian</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

in order to configure jboss to use a datasource all we need to do is to create a file that has “-ds” in its name, so go ahead and create a file called jbossas-ds.xml that is located under “src/test/resources” and that file should look like this.

<?xml version="1.0" encoding="UTF-8"?>
<datasources xmlns="http://www.jboss.org/ironjacamar/schema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="

http://www.jboss.org/ironjacamar/schema

        http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
    <datasource enabled="true"
        jndi-name="jdbc/arquillian"
        pool-name="ArquillianEmbeddedH2Pool">
        <connection-url>jdbc:h2:mem:arquillian;DB_CLOSE_DELAY=-1</connection-url>
        <driver>h2</driver>
    </datasource>
</datasources>

we need to make some changes to our pom file as well, we need to tell our different profiles where our resources are located. So what we need to do is to add a section under each profile we will use.
So for our glassfish-embedded profile add the following code after the tab


    <build>
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
            </testResource>
            <testResource>
                <directory>src/test/resources/glassfish-embedded</directory>
            </testResource>
        </testResources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.12.2</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.config.file>
                            ${project.build.testOutputDirectory}/logging.properties
                        </java.util.logging.config.file>
                        <derby.stream.error.file>
                            ${project.build.testOutputDirectory}/derby.log
                        </derby.stream.error.file>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
    </build>

and for our jbossas-managed profile add the following


    <build>
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
            </testResource>
            <testResource>
                <directory>src/test/resources/jbossas-managed</directory>
            </testResource>
        </testResources>
</build>

We are now ready to start writing some java code. But before we do that lets discuss what we will need to do.
The previous demo step-4-tdd-development-using-arquillian we wrote some tests for our shopping cart, we will need to make adjustments in there otherwise that test case will break.
We are going to make a new test file as well where we will test the repository.
And we will also create two entities, OrderEntity and ProductEntity and we will also create corresponding DTO object for each entity called OrderDTO and ProductDTO.
What is it we want to do?
We want to add products to our shopping cart, once we are done we want to be able to place an order.
Each order will have some properties like:
order id,
status and
a list of products

each product will also have some properties
product id,
name,
description and
a price

So lets go ahead and create our entities. Go ahead and rename the Order.java to OrderEntity.java and Product.java to ProductEntity.java

Open the OrderEntity.java file
1. We need to tell the class it is an entity, we do that by adding the @Entity annotation above the class definition.
2. We need to map our class properties to the database table.
Add the @Id and @GeneratedValue to our private Long id;
And we need to make a OneToMany join between our order and products, like we said above, each order contains a list of products.
Add the @OneToMany annotation to the private Listproducts and add the following properties to it.
mappedBy=”order”
fetch=FetchType.LAZY
cascade=CascadeType.ALL

This means that there will be a property called order in our products entity, we will get the list of products when we access the order, if we wanted to preload the list we could have used fetch=FetchType.EAGER but this will cause performance decrease.
The cascade property defines the set of cascagable operations that are propagated to the associated entity.

Next we need to create constructors, getters/setters and ovveride the hashCode, equals and toString methods for our entity.
Create a default constructor and one that populates the id, and products fields.
In both constructors we will set the status to “CREATED”, this is the default status.

Since we are using a OneToMany relationship between the order and product tables we need to be able to add the products to our list, in order to guarantee that this is done we should implement the following method

public void addProduct(ProductEntity product){
this.products.add(product);
if(product.getOrder() != this){
product.setOrder(this);
}
}

And finally we are going to make two methods that allows us to convert between OrderDTO and OrderEntity, the @Transient means that we will not serialize this to the database.

@Transient
public OrderDTO asDTO(){
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderId(this.id);
orderDTO.setStatus(this.status);
List products = new ArrayList();
for(ProductEntity product : this.products){
ProductDTO productDTO = new ProductDTO();
productDTO.setId(product.getId());
productDTO.setName(product.getName());
productDTO.setDescription(product.getDescription());
productDTO.setPrice(product.getPrice());
productDTO.setOrder(orderDTO);
products.add(productDTO);
}
orderDTO.setProducts(products);

return orderDTO;
}

public static OrderEntity fromDTO(OrderDTO orderDTO){

OrderEntity orderEntity = new OrderEntity();
orderEntity.setStatus(orderDTO.getStatus());
List productList = new ArrayList();
for(ProductDTO dto : orderDTO.getProducts()){
productList.add(ProductEntity.fromDTO(dto));
}
orderEntity.setProducts(productList);
return orderEntity;
}

We have one final thing to do before we are with this entity, that is to create a NamedQuery that will allow us to query the table.
We want to create a query that will find a specific order, so create

public static final String FIND_ORDER = “findOrder”;

and after the @Entity add the following

@NamedQueries({
@NamedQuery(name=OrderEntity.FIND_ORDER,
query=”select o from OrderEntity o WHERE o.id = :o rderId”)
})

Our java class should now look like this…

package com.bekkestad.examples.tutorial;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

@Entity
@NamedQueries({
@NamedQuery(name=OrderEntity.FIND_ORDER,
query=”select o from OrderEntity o WHERE o.id = :o rderId”)
})
public class OrderEntity {

public static final String FIND_ORDER = “findOrder”;

@Id
@GeneratedValue
private Long id;

@OneToMany(mappedBy=”order”, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private List products = new ArrayList();

private String status;

public void addProduct(ProductEntity product){
this.products.add(product);
if(product.getOrder() != this){
product.setOrder(this);
}
}

public OrderEntity(){
this.status = “CREATED”;
}

public OrderEntity(Long orderId, List products) {
super();
this.id = orderId;
this.products = products;
this.status = “CREATED”;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public List getProducts() {
return products;
}

public void setProducts(List products) {
this.products = products;
}

@Override
public String toString() {
return “Order@” + hashCode() + “[id:" + id + "; status:" + status + "; products:" + (products==null?"NULL":products.size())+ "]“;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OrderEntity other = (OrderEntity) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}

@Transient
public OrderDTO asDTO(){
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderId(this.id);
orderDTO.setStatus(this.status);
List products = new ArrayList();
for(ProductEntity product : this.products){
ProductDTO productDTO = new ProductDTO();
productDTO.setId(product.getId());
productDTO.setName(product.getName());
productDTO.setDescription(product.getDescription());
productDTO.setPrice(product.getPrice());
productDTO.setOrder(orderDTO);
products.add(productDTO);
}
orderDTO.setProducts(products);

return orderDTO;
}

public static OrderEntity fromDTO(OrderDTO orderDTO){

OrderEntity orderEntity = new OrderEntity();
orderEntity.setStatus(orderDTO.getStatus());
List productList = new ArrayList();
for(ProductDTO dto : orderDTO.getProducts()){
productList.add(ProductEntity.fromDTO(dto));
}
orderEntity.setProducts(productList);
return orderEntity;
}

}

Lets now go ahead and do the same for the ProductEntity class
that class should look like this

package com.bekkestad.examples.tutorial;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Entity
public class ProductEntity implements Serializable{

private static final long serialVersionUID = 1L;

public static ProductEntity fromDTO(ProductDTO productDTO){
ProductEntity productEntity = new ProductEntity();
productEntity.setName(productDTO.getName());
productEntity.setDescription(productDTO.getDescription());
productEntity.setPrice(productDTO.getPrice());

if(productDTO.getOrder() != null){
productEntity.setOrder(OrderEntity.fromDTO(productDTO.getOrder()));
}

return productEntity;
}

@Id
@GeneratedValue
private Long id;

@NotNull
@Size(min=3, max=50)
private String name;

@Size(max=2000)
private String description;

@NotNull
@Column(precision=10, scale=2)
private Double price;

@ManyToOne
private OrderEntity order;

@Transient
public ProductDTO asDTO(){
ProductDTO productDTO = new ProductDTO();
productDTO.setId(this.id);
productDTO.setName(this.name);
productDTO.setDescription(this.description);
productDTO.setPrice(this.price);
productDTO.setOrder(this.order.asDTO());

return productDTO;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ProductEntity other = (ProductEntity) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}

public String getDescription() {
return description;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public OrderEntity getOrder() {
return order;
}

public Double getPrice() {
return price;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}

public void setDescription(String description) {
this.description = description;
}

public void setId(Long id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

public void setOrder(OrderEntity order) {
this.order = order;
if(!order.getProducts().contains(this)){
order.getProducts().add(this);
}
}

public void setPrice(Double price) {
this.price = price;
}

@Override
public String toString() {
return “Product@” + hashCode() + “[id:" + id + "; name:" + name + ";]“;
}

}

Next we are going to create our DTOs
Create a new class called OrderDTO and another called ProductDTO, these are just POJOs mapping to the entity.
Here is the code for the OrderDTO.

package com.bekkestad.examples.tutorial;

import java.util.List;

public class OrderDTO {
private Long orderId;
private String status;
private List products;

public OrderDTO() {
super();
}

public Long getOrderId() {
return orderId;
}

public List getProducts() {
return products;
}

public String getStatus() {
return status;
}

public void setOrderId(Long orderId) {
this.orderId = orderId;
}

public void setProducts(List products) {
this.products = products;
}

public void setStatus(String status) {
this.status = status;
}

}

And the ProductDTO

package com.bekkestad.examples.tutorial;

public class ProductDTO {
private Long id;
private String description;
private String name;
private Double price;
private OrderDTO order;
/**
*
*/
public ProductDTO() {
super();
}

public String getDescription() {
return description;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public OrderDTO getOrder() {
return order;
}

public Double getPrice() {
return price;
}

public void setDescription(String description) {
this.description = description;
}

public void setId(Long id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

public void setOrder(OrderDTO order) {
this.order = order;
}

public void setPrice(Double price) {
this.price = price;
}
}

Now we are ready to start our implementation.
Lets start by opening the OrderRepository.java
We do no longer need to use the method Long getOrderId(); so go ahead and remove that one.
We need to make a change to the
Long placeOrder(List order); it should now take a list of ProductDTO
Long placeOrder(List order);
And the getOrder should return an OrderDTO instead of an Order

The file should now look like this

package com.bekkestad.examples.tutorial;

import java.util.List;

import javax.ejb.Local;

@Local
public interface OrderRepository {

Long placeOrder(List order);
OrderDTO getOrder(Long orderId);
}

You should now have many errors in your project, do not worry about that since we will deal with them later.

Open the OrderRepositoryImpl.java
Lets start by removing what is not needed.
remove these…

private Map orders;
private Long orderId = 0L;

@Override
public Long getOrderId(){
return orderId;
}

@PostConstruct
void initialize(){
orders = new HashMap();
}

First we are going to fix the placeOrder method
1. Change the parameter to ProductDTO
2. remove orders.put(++orderId, new Order(orderId, order, “CREATED”));

We now need to create a new instance of an OrderEntity,
then we should look over all the products we added and persist them to the database and then add them to the OrderEntity we just created.
Once this is done we will persist the OrderEntity to the database.
We then need to flush the EntityManager to load the products and the last thing we will do is to return the newly created orderId;
That code should look like this, since this method writes to the database i am creating a Lock on it.

@Override
@Lock(LockType.WRITE)
public Long placeOrder(List products) {

OrderEntity orderEntity = new OrderEntity();
try {
for(ProductDTO productDTO : products){
ProductEntity productEntity = ProductEntity.fromDTO(productDTO);
em.persist(productEntity);
orderEntity.addProduct(productEntity);
}
} catch (Exception e1) {
e1.printStackTrace();
}

try {
em.persist(orderEntity);
em.flush();
} catch (Exception e) {
e.printStackTrace();
}

return orderEntity.getId();
}

The next thing we need to do is to be able to get the order, change the return type from Order to OrderDTO
remove the return orders.get(orderId);
and create a new OrderEntity.
We are going to use the NamedQuery that we defined earlier, and add a parameter called order Id, even though not needed we are going to specify that we just want one result.
Once this is done we will return the OrderEntity as a DTO object.
That method should look like this

@Override
public OrderDTO getOrder(Long orderId) {
OrderEntity orderEntity = null;

try {
orderEntity = (OrderEntity)em.createNamedQuery(OrderEntity.FIND_ORDER)
.setParameter(“orderId”, orderId).getSingleResult();

} catch (NoResultException nre) {
nre.printStackTrace();
}

return orderEntity.asDTO();
}

Our complete file should look like this

package com.bekkestad.examples.tutorial;

import java.util.List;

import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;

@Singleton
@Lock(LockType.READ)
public class OrderRepositoryImpl implements OrderRepository {

@PersistenceContext
EntityManager em;

@Override
@Lock(LockType.WRITE)
public Long placeOrder(List products) {

OrderEntity orderEntity = new OrderEntity();
try {
for(ProductDTO productDTO : products){
ProductEntity productEntity = ProductEntity.fromDTO(productDTO);
em.persist(productEntity);
orderEntity.addProduct(productEntity);
}
} catch (Exception e1) {
e1.printStackTrace();
}

try {
em.persist(orderEntity);
em.flush();
} catch (Exception e) {
e.printStackTrace();
}

return orderEntity.getId();
}

@Override
public OrderDTO getOrder(Long orderId) {
OrderEntity orderEntity = null;

try {
orderEntity = (OrderEntity)em.createNamedQuery(OrderEntity.FIND_ORDER)
.setParameter(“orderId”, orderId).getSingleResult();

} catch (NoResultException nre) {
nre.printStackTrace();
}

return orderEntity.asDTO();
}

}

Next we should fix our ShoppingCart.java, so go ahead and open it.

Change all instances of Product to ProductDTO, the code should now look like this

package com.bekkestad.examples.tutorial;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;

@SessionScoped
public class ShoppingCart implements Serializable {

private static final long serialVersionUID = 1L;
private Map shoppingCartMap;

@EJB
private OrderRepository order;

public void addProduct(ProductDTO product){
shoppingCartMap.put(product.getId(), product);
}

public void removeProduct(Long productId){
shoppingCartMap.remove(productId);
}

public List getShoppingCart(){
return Collections.unmodifiableList(new ArrayList(shoppingCartMap.values()));
}

public Long placeOrder() throws Exception{
Long orderId = order.placeOrder(getShoppingCart());
shoppingCartMap.clear();
return orderId;
}

public String getOrderStatus(Long orderId) throws Exception{
return order.getOrder(orderId).getStatus();
}

@PostConstruct
void initialize(){
shoppingCartMap = new HashMap();
}
}

Now we should focus on the testing.
The first thing we should do is to fix the broken tests in ShoppingCartTest.java
Change all instances of Product to ProductDTO,
then after the NR_OF_PRODUCTS_TO_TEST = 4 add a
private static Long orderId = 0L;

We no longer need the
@EJB
OrderRepository order so go ahead and remove that.

Next go to the should_be_able_to_place_order() method and have the
shoppingCart.placeOrder() assign the value to the global variable we created rather than the local one.

and finally in the should_be_able_to_get_order_status() method we will not get the order Id no more, since we have it stored in the global variable so go ahead and remove the
Long orderId = order.getOrderId();
and we are not even using the order variable so instead of
String status = order.getOrder(orderId).getStatus(); all we need to do is to call the shopping cart, so change this to String status = shoppingCart.getOrderStatus(orderId);

Before we can test this there is one final thing we need to do.
Our createDeployment method is not configure correctly, so we need to make a lot of changes there. Replace that whole method with the following one.

@Deployment
public static Archive createDeployment(){
return ShrinkWrap.create(WebArchive.class, “test.war”)
.addClasses(ShoppingCart.class, ProductDTO.class, OrderDTO.class, OrderEntity.class, ProductEntity.class, OrderRepository.class, OrderRepositoryImpl.class)
.addAsResource(“test-persistence.xml”, “META-INF/persistence.xml”)
.addAsWebInfResource(“jbossas-ds.xml”)
.addAsWebInfResource(EmptyAsset.INSTANCE, “beans.xml”);
}

We are using a WebArchive instead of a JavaArchive, we need to add many more classes, copy the test-persistence.xml to the right place, put the jboss-ds file in the WEB-INF folder.

Our class should now look like this.

package com.bekkestad.examples.tutorial;

import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;
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;

@RunWith(Arquillian.class)
public class ShoppingCartTest {

private static final List PRODUCT_LIST = new ArrayList();
private static final int NR_OF_PRODUCTS_TO_TEST = 4;
private static Long orderId = 0L;
static {

for(int i = 0; i < NR_OF_PRODUCTS_TO_TEST; i++){
ProductDTO product = new ProductDTO();

product.setId(i+1L);
product.setName(“PRODUCT” + (i + 1));
product.setDescription(“This is product ” + (i+1));
product.setPrice(10D * (i + 1));
PRODUCT_LIST.add(product);
}
}

@Deployment
public static Archive createDeployment(){
return ShrinkWrap.create(WebArchive.class, “test.war”)
.addClasses(ShoppingCart.class, ProductDTO.class, OrderDTO.class, OrderEntity.class, ProductEntity.class, OrderRepository.class, OrderRepositoryImpl.class)
.addAsResource(“test-persistence.xml”, “META-INF/persistence.xml”)
.addAsWebInfResource(“jbossas-ds.xml”)
.addAsWebInfResource(EmptyAsset.INSTANCE, “beans.xml”);
}

@Inject
ShoppingCart shoppingCart;

@Test
@InSequence(1)
public void should_be_able_to_add_products_to_cart(){
addProductsToCart();

List productsInCart = shoppingCart.getShoppingCart();
Assert.assertEquals(NR_OF_PRODUCTS_TO_TEST, productsInCart.size());
}

@Test
@InSequence(2)
public void should_be_able_to_get_the_shopping_cart(){
addProductsToCart();

List productsInCart = shoppingCart.getShoppingCart();

int temp = 0;
for(ProductDTO product : productsInCart){
Assert.assertEquals(PRODUCT_LIST.get(temp).getId(), product.getId());
Assert.assertEquals(PRODUCT_LIST.get(temp).getName(), product.getName());
Assert.assertEquals(PRODUCT_LIST.get(temp).getDescription(), product.getDescription());
Assert.assertEquals(PRODUCT_LIST.get(temp).getPrice(), product.getPrice());
temp++;
}
if(temp == 0)
Assert.fail(“THE CART IS EMPTY”);
}

@Test
@InSequence(3)
public void should_be_able_to_remove_product_from_cart(){
addProductsToCart();

int nrOfProductsToRemove = 2;
for(int i = 0; i < nrOfProductsToRemove; i++){
shoppingCart.removeProduct((i + 1)*1L);
}
List productsInCart = shoppingCart.getShoppingCart();
Assert.assertEquals(NR_OF_PRODUCTS_TO_TEST-nrOfProductsToRemove, productsInCart.size());
}

@Test
@InSequence(4)
public void should_be_able_to_place_order() throws Exception{
addProductsToCart();
orderId = shoppingCart.placeOrder();
List productsInCart = shoppingCart.getShoppingCart();

Assert.assertEquals(true, orderId>0);
Assert.assertEquals(0, productsInCart.size());
}

@Test
@InSequence(5)
public void should_be_able_to_get_order_status() throws Exception{
String status = shoppingCart.getOrderStatus(orderId);

Assert.assertEquals(“CREATED”, status);
}

private void addProductsToCart(){
for(ProductDTO product : PRODUCT_LIST){
shoppingCart.addProduct(product);
}
}
}

We can now run the tests on our old test cases.
But we also want to test the repository itself.
So go ahead and create a new class file called OrderRepositoryTest.java

Comparing this one to the previous ShoppingCartTest.java, it will be very similar to that one.

1. We will have a global private static Long orderId = 0L;
2. We will have the same createDeployment as in ShoppingCartTest
3. We will have two @Test methods
should_be_able_to_place_order and
should_be_able_to_get_order

4. We will now use the
@EJB
OrderRepository repository;

Lets start with the first test case,
We need to create a couple of ProductsDTOs, add them to a List
and then call the repository.placeOrder(products) method and we will test
that the returning orderId is not 0L.
The code should look something like this

@Test
@InSequence(1)
public void should_be_able_to_place_order(){
List products = new ArrayList();

ProductDTO product1 = new ProductDTO();
product1.setName(“PRODUCT1″);
product1.setDescription(“PRODUCT1 Description”);
product1.setPrice(10D);

ProductDTO product2 = new ProductDTO();
product2.setName(“PRODUCT2″);
product2.setDescription(“PRODUCT2 Description”);
product2.setPrice(20D);

products.add(product1);
products.add(product2);

orderId = repository.placeOrder(products);

Assert.assertTrue(orderId != 0L);
}

The second @Test method is also very similar
We will use the orderId returned by the previous test casem send it in as a parameter to the
repository.getOrder(orderId) method.
After that we should get an OrderDTO back, that we will get the products, check that the size of the products is the same as the size we added in the previous test and we will that the OrderDTO returned has the same orderId and the one we used to send into the method.
The code should now look something like this.

@Test
@InSequence(2)
public void should_be_able_to_get_order(){
OrderDTO order = repository.getOrder(orderId);

List products = order.getProducts();
Assert.assertEquals(2, products.size());
Assert.assertEquals(orderId, order.getOrderId());
}

The final code should be this

package com.bekkestad.examples.tutorial;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.EJB;

import junit.framework.Assert;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;
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.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class OrderRepositoryTest {

private static Long orderId = 0L;

@Deployment
public static Archive createDeployment(){
return ShrinkWrap.create(WebArchive.class, “test.war”)
.addClasses(ProductDTO.class, OrderDTO.class, OrderEntity.class, ProductEntity.class, OrderRepository.class, OrderRepositoryImpl.class)
.addAsResource(“test-persistence.xml”, “META-INF/persistence.xml”)
.addAsWebInfResource(“jbossas-ds.xml”)
.addAsWebInfResource(EmptyAsset.INSTANCE, “beans.xml”);
}

@EJB
OrderRepository repository;

@Test
@InSequence(1)
public void should_be_able_to_place_order(){
List products = new ArrayList();

ProductDTO product1 = new ProductDTO();
product1.setName(“PRODUCT1″);
product1.setDescription(“PRODUCT1 Description”);
product1.setPrice(10D);

ProductDTO product2 = new ProductDTO();
product2.setName(“PRODUCT2″);
product2.setDescription(“PRODUCT2 Description”);
product2.setPrice(20D);

products.add(product1);
products.add(product2);

orderId = repository.placeOrder(products);

Assert.assertTrue(orderId != 0L);
}

@Test
@InSequence(2)
public void should_be_able_to_get_order(){
OrderDTO order = repository.getOrder(orderId);

List products = order.getProducts();
Assert.assertEquals(2, products.size());
Assert.assertEquals(orderId, order.getOrderId());
}
}

We are now done, run all the tests, use the different containers and you should have green on all tests.
You can get the code for this example on GitHub
In the next session we will be looking at Selenium for testing the web layer

Go back to Index



Viewing all articles
Browse latest Browse all 26

Trending Articles