Embedded databases

Mapping persistence of domain entities is usually defined using JPA annotations. Validating this mapping before an actual server deployment prevents careless mistakes and saves time.

In order to verify a correct database mapping, a database is required. Besides using deployed environment database instances, embedded databases provide similar verification with fast feedback. Embedded container tests running on frameworks such as Arquillian can be used to access this functionality. However, for basic verification it's not necessary for the application to run inside a container.

JPA ships with the possibility to run standalone, in any Java SE environment. We can make use of this and write test cases that wire up the JPA configuration and connect against an embedded or local database.

Imagine a car part that is manufactured and assembled in the car manufacture. The car part domain entity is mapped with JPA as follows:

@Entity
@Table(name = "car_parts")
public class CarPart {

    @Id
    @GeneratedValue
    private long id;

    @Basic(optional = false)
    private String order;

    @Enumerated(STRING)
    @Basic(optional = false)
    private PartType type;

    ...
}

In order to verify correct persistence, a test entity bean should at least be persisted and reloaded from the database. The following code snippet shows an integration test that sets up a standalone JPA persistence:

import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class CarPartIT {

    private EntityManager entityManager;
    private EntityTransaction transaction;

    @Before
    public void setUp() {
        entityManager = Persistence.createEntityManagerFactory("it").createEntityManager();
        transaction = entityManager.getTransaction();
    }

    @Test
    public void test() {
        transaction.begin();

        CarPart part = new CarPart();
        part.setOrder("123");
        part.setType(PartType.CHASSIS);
        entityManager.merge(part);

        transaction.commit();
    }
}

Since the persistence runs standalone, there is no container taking care of handling transactions. The test case does this programmatically, as well as setting up the entity manager, using the persistence unit it. The persistence unit is configured in test scope persistence.xml. For this test purpose it's sufficient to configure a resource local transactional unit:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" 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_2.xsd">

    <persistence-unit name="it" transaction-type="RESOURCE_LOCAL">
        <class>com.example.cars.entity.CarPart</class>

        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:derby:./it;create=true"/>
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
        </properties>
    </persistence-unit>
</persistence>

The involved entity classes such as CarPart have to be specified explicitly, since there is no container that takes care of annotation scanning. The JDBC configuration points to an embedded database, in this case Apache Derby.

The enterprise project does not include the Java EE implementation, only the API. Therefore, an JPA implementation, such as EclipseLink, is added as a test dependency, together with the Derby database.

This integration test provides faster feedback for configuration mismatches and careless mistakes by validating the persistence mapping locally. For example, the shown test case would fail because the order property of the CarPart type isn't able to be mapped, since order is a reserved SQL keyword. The solution to this is to change the column mapping, for example, by renaming the column with @Column(name = "part_order").

This is a typical example of mistakes developers make while configuring the persistence. Preventing these errors, that otherwise won't be detected before deployment time, provides faster feedback and saves time and effort.

Of course, this approach will not find all database related integration mismatches. There is no container being used and persistence errors, for example, related to concurrent transactions, won't be found before fully-fledged system tests are executed. Still, it provides a helpful first verification in the pipeline.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.182.66