Mam problem z konfiguracją jednej aplikacji Spring, która używa JPA z Hibernate do testowania jednostkowego. Mam 2 pliki persistence.xml jeden do produkcji i jeden do testów jednostkowych. Do testów:Konfigurowanie aplikacji Spring JPA z Hibernate do testowania jednostkowego (ładowanie z opóźnieniem)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="prod_pu" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/ds_prod</jta-data-source>
<properties>
<property name="hibernate.bytecode.use_reflection_optimizer" value="false"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
<property name="hibernate.connection.password" value="passsample"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:urlsample"/>
<property name="hibernate.connection.username" value="usernamesample"/>
<property name="hibernate.default_schema" value="schemassample"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
</properties>
</persistence-unit>
</persistence>
do testowania:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="test_pu" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.bytecode.use_reflection_optimizer" value="false"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
<property name="hibernate.connection.password" value="passsample"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:urlsample"/>
<property name="hibernate.connection.username" value="usernamesample"/>
<property name="hibernate.default_schema" value="schemasample"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
</properties>
</persistence-unit>
</persistence>
Różnica jest w testach jednostkowych dont używać żadnych transakcji JTA (Global), używam tylko lokalne transakcje.
Konfiguracja wiosna dla produkcji jest:
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/ds_prod"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="persAnnoBeanPostProc" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
<property name="persistenceUnits">
<map>
<entry key="prod_pu" value="persistence/prod_pu"/>
</map>
</property>
</bean>
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<context:component-scan base-package="com.sample.packagename" />
<tx:jta-transaction-manager/>
Konfiguracja sprężynowe dla testów jednostkowych:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- This workaround is necessary because Spring is buggy
Instead of including the test-classes/META-INF the spring always search into classes/META-INF and ignores the one from test-classes
-->
<property name="persistenceXmlLocation" value="META-INF/persistence-test.xml" />
<property name="persistenceUnitName" value="test_pu" />
</bean>
<bean id="persAnnoBeanPostProc" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="persistenceUnitName" value="test_pu" />
</bean>
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<context:component-scan base-package="com.sample.packagename" />
zajęło mi tyle samo czasu na decydowania mnie do tej konfiguracji aplikacji potrzebuje globalnych transakcji, ponieważ mamy transakcje między JMS i DB, ale w teście jednostki definiuję tylko transakcje lokalne, więc jestem ograniczony w testowaniu aplikacji. Przy tych limitach definiuję moje testy jednostkowe.
Teraz mam problem z Hibernate i LAZY ładowanie relacji. W teście Unit sesja EntityManager zamyka się po znalezieniu metod, a następnie i proxy dla LAZY ładowanie nie działa. (To jest z definicji w Hibernate zgodnie z oczekiwaniami) Moim problemem jest Perspektywa fasoliNarzędziPrezentacjaBeanPostProcessor ma jakikolwiek zestaw nazw jednostkowych dla testów jednostkowych i za każdym razem, gdy znajduje adnotację @PersistenceContext wstawia nowy EntityManger stworzony z EntityManagerFactory zdefiniowany w konfiguracji wiosennej do testowania. Teraz test jednostki jest posiadanie elementu @PersistenceContext EntityManager i klasy DAO TOO:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:testConfiguration.xml"})
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public class ConnectionTest {
@PersistenceContext
EntityManager entityManager;
Logger log = Logger.getLogger(ConnectionTest.class);
@Resource(name = "syDbVersionDao")
SyDbVersionDao dbVersionDao;
@Test
public void testChanging() {
String oldVer = dbVersionDao.getCurrentVersion();
assertNotNull(oldVer);
}
}
@Component
public class SyDbVersionDao extends SyDbVersionHome {
@PersistenceContext
private EntityManager entityManager;
public String getCurrentVersion() {
SyDbVersion res = getLastRecord();
if (res == null) return "";
return res.getVersion();
}
public SyDbVersion getLastRecord(){
Query query = entityManager.createQuery("from SyDbVersion v order by v.installationDate desc");
query.setMaxResults(1);
return (SyDbVersion) query.getSingleResult();
}
}
/**
* Home object for domain model class SyDbVersion.
* @see com.tsystems.ac.fids.web.persistence.jpa.SyDbVersion
* @author Hibernate Tools, generated!
*/
@Stateless
public class SyDbVersionHome {
private static final Log log = LogFactory.getLog(SyDbVersionHome.class);
@PersistenceContext private EntityManager entityManager;
public void persist(SyDbVersion transientInstance) {
log.debug("persisting SyDbVersion instance");
try {
entityManager.persist(transientInstance);
log.debug("persist successful");
}
catch (RuntimeException re) {
log.error("persist failed", re);
throw re;
}
}
public void remove(SyDbVersion persistentInstance) {
log.debug("removing SyDbVersion instance");
try {
entityManager.remove(persistentInstance);
log.debug("remove successful");
}
catch (RuntimeException re) {
log.error("remove failed", re);
throw re;
}
}
public SyDbVersion merge(SyDbVersion detachedInstance) {
log.debug("merging SyDbVersion instance");
try {
SyDbVersion result = entityManager.merge(detachedInstance);
log.debug("merge successful");
return result;
}
catch (RuntimeException re) {
log.error("merge failed", re);
throw re;
}
}
public SyDbVersion findById(long id) {
log.debug("getting SyDbVersion instance with id: " + id);
try {
SyDbVersion instance = entityManager.find(SyDbVersion.class, id);
log.debug("get successful");
return instance;
}
catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
}
Klasa SyDbVersionHome jest generowany z Hibernate Tools z DB i klasy Entity też.
Teraz problemem jest wiersz: Instancja SyDbVersion = entityManager.find (SyDbVersion.class, id); Za każdym razem, gdy wracam z metody szukania, sesja jest zamknięta, więc leniwi członkowie nie są już dostępni.
Zastanawiam się, jak poprawnie skonfigurować parametr PersistenceAnnotationBeanPostProcessor z nazwą jednostki trwałej, ale komponent bean wyszukuje jednostkę trwałości w JNDI i nie można znaleźć odpowiedniego czasu na zarejestrowanie wpisu JNDI dla jednostki utrwalania.
W produkcji, ponieważ ustawiłem parametr PersistenceAnnotationBeanPostProcessor, EntityManager jest następnie poprawnie udostępniany, a sesja nie jest zamykana za każdym razem po znalezieniu.
Innym rozwiązaniem będzie użycie OpenEJB lub embedded-glassfish do symulacji/posiadania serwera aplikacji w testach jednostkowych (staną się wtedy testami integracyjnymi).
Jakie opcje muszę zmodyfikować w konfiguracji sprężynowej lub w kodzie, aby uniknąć tego problemu podczas testowania urządzenia?