In an EE6/CDI/JPA project, a test src/test/resources/META-INF/persistence.xml
is picked up just fine without any further configuration.
When using JPA in Spring, the following works in the application context used for testing:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--
JPA requires META-INF/persistence.xml, but somehow prefers the one
in classes/META-INF over the one in test-classes/META-INF. Spring
to the rescue, as it allows for setting things differently, like by
referring to "classpath:persistence-TEST.xml". Or, simply referring
to "META-INF/persistence.xml" makes JPA use the test version too:
-->
<property name="persistenceXmlLocation" value="META-INF/persistence.xml" />
<!-- As defined in /src/test/resources/META-INF/persistence.xml -->
<property name="persistenceUnitName" value="myTestPersistenceUnit" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
</bean>
</property>
</bean>
Here, /src/test/resources/META-INF/persistence.xml
(copied into target/test-classes
) would be preferred over /src/main/resources/META-INF/persistence.xml
(copied into target/classes
).
Unfortunately, the location of the persistence.xml
file also determines the so-called "persistence unit's root", which then determines which classes are scanned for @Entity
annotations. So, using /src/test/resources/META-INF/persistence.xml
would scan classes in target/test-classes
, not classes in target/classes
(where the classes that need to be tested would live).
Hence, for testing, one would need to explicitly add <class>
entries to persistence.xml
, to avoid java.lang.IllegalArgumentException: Not an entity: class ...
. The need for <class>
entries can be avoided by using a different file name, like persistence-TEST.xml
, and put that file in the very same folder as the regular persistence.xml
file. The Spring context from your test folder can then just refer to <property name="persistenceXmlLocation" value="META-INF/persistence-TEST.xml" />
, and Spring will find it for you in src/main
.
As an alternative, one might be able to keep persistence.xml
the same for the actual application and the tests, and only define one in src/main
. Most configuration such as the drivers, dialect and optional credentials can be done in the Spring context instead. Also settings such as hibernate.hbm2ddl.auto
can be passed in the context:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- For example: com.mysql.jdbc.Driver or org.h2.Driver -->
<property name="driverClassName" value="#{myConfig['db.driver']}" />
<!-- For example: jdbc:mysql://localhost:3306/myDbName or
jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 -->
<property name="url" value="#{myConfig['db.url']}" />
<!-- Ignored for H2 -->
<property name="username" value="#{myConfig['db.username']}" />
<property name="password" value="#{myConfig['db.password']}" />
</bean>
<bean id="jpaAdaptor"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- For example: org.hibernate.dialect.MySQL5Dialect or
org.hibernate.dialect.H2Dialect -->
<property name="databasePlatform" value="#{myConfig['db.dialect']}" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="jpaProperties">
<props>
<!-- For example: validate, update, create or create-drop -->
<prop key="hibernate.hbm2ddl.auto">#{myConfig['db.ddl']}</prop>
<prop key="hibernate.show_sql">#{myConfig['db.showSql']}</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>