2010-03-24 23 views
9

Estoy intentando crear pruebas JUnit para mis clases JPA DAO, usando Spring 2.5.6 y JUnit 4.8.1.Inyección de Dependencia con Spring/Junit/JPA

Mi caso de prueba es el siguiente:


@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations={"classpath:config/jpaDaoTestsConfig.xml"}) 
public class MenuItem_Junit4_JPATest extends BaseJPATestCase { 

    private ApplicationContext context; 
    private InputStream dataInputStream; 
    private IDataSet dataSet; 

    @Resource 
    private IMenuItemDao menuItemDao; 

    @Test 
    public void testFindAll() throws Exception { 
     assertEquals(272, menuItemDao.findAll().size()); 
    } 

    ... Other test methods ommitted for brevity ... 
} 

Tengo el siguiente en mi jpaDaoTestsConfig.xml:


<?xml version="1.0" encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:p="http://www.springframework.org/schema/p" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd 
          http://www.springframework.org/schema/tx 
          http://www.springframework.org/schema/tx/spring-tx.xsd"> 

    <!-- uses the persistence unit defined in the META-INF/persistence.xml JPA configuration file --> 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="CONOPS_PU" /> 
    </bean> 

    <bean id="groupDao" class="mil.navy.ndms.conops.common.dao.impl.jpa.GroupDao" lazy-init="true" /> 
    <bean id="permissionDao" class="mil.navy.ndms.conops.common.dao.impl.jpa.PermissionDao" lazy-init="true" /> 
    <bean id="applicationUserDao" class="mil.navy.ndms.conops.common.dao.impl.jpa.ApplicationUserDao" lazy-init="true" /> 
    <bean id="conopsUserDao" class="mil.navy.ndms.conops.common.dao.impl.jpa.ConopsUserDao" lazy-init="true" /> 

    <bean id="menuItemDao" class="mil.navy.ndms.conops.common.dao.impl.jpa.MenuItemDao" lazy-init="true" /> 

<!-- enables interpretation of the @Required annotation to ensure that dependency injection actually occures --> 
    <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/> 

    <!-- enables interpretation of the @PersistenceUnit/@PersistenceContext annotations providing convenient 
     access to EntityManagerFactory/EntityManager --> 
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> 

    <!-- transaction manager for use with a single JPA EntityManagerFactory for transactional data access 
     to a single datasource --> 
    <bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory"/> 
    </bean> 

    <!-- enables interpretation of the @Transactional annotation for declerative transaction managment 
     using the specified JpaTransactionManager --> 
    <tx:annotation-driven transaction-manager="jpaTransactionManager" proxy-target-class="false"/> 

</beans> 

Ahora, cuando trato de ejecutar esto, me sale el siguiente:

SEVERE: Caught exception while allowing TestExecutionListener [org.springframewor[email protected]fa60fa6] to prepare test instance [null(mil.navy.ndms.conops.common.dao.impl.MenuItem_Junit4_JPATest)] 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mil.navy.ndms.conops.common.dao.impl.MenuItem_Junit4_JPATest': Injection of resource fields failed; nested exception is java.lang.IllegalStateException: Specified field type [interface javax.persistence.EntityManagerFactory] is incompatible with resource type [javax.persistence.EntityManager] 
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessAfterInstantiation(CommonAnnotationBeanPostProcessor.java:292) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:959) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:329) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:255) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:93) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:130) 
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61) 
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:54) 
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:52) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) 
Caused by: java.lang.IllegalStateException: Specified field type [interface javax.persistence.EntityManagerFactory] is incompatible with resource type [javax.persistence.EntityManager] 
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.checkResourceType(InjectionMetadata.java:159) 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.(PersistenceAnnotationBeanPostProcessor.java:559) 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$1.doWith(PersistenceAnnotationBeanPostProcessor.java:359) 
    at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:492) 
    at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:469) 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findPersistenceMetadata(PersistenceAnnotationBeanPostProcessor.java:351) 
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(PersistenceAnnotationBeanPostProcessor.java:296) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:745) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:448) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) 
    at java.security.AccessController.doPrivileged(AccessController.java:219) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168) 
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:435) 
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:409) 
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:537) 
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:180) 
    at org.springframework.beans.factory.annotation.InjectionMetadata.injectFields(InjectionMetadata.java:105) 
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessAfterInstantiation(CommonAnnotationBeanPostProcessor.java:289) 
    ... 18 more 

Parece que me está diciendo que está tratando de almacenar un objeto EntityManager en un EntityManagerFactory fi campo, pero no entiendo cómo o por qué. Mis clases DAO aceptan un EntityManager y EntityManagerFactory a través del atributo @PersistenceContext, y funcionan si los descargo y los ejecuto sin el atributo @ContextConfiguration (es decir, si solo uso el XmlApplcationContext para cargar el DAO y el EntityManagerFactory directamente en setUp()).

Cualquier apreciación sería apreciada.

Respuesta

23

Estas son las combinaciones correctas de anotación + Interfaz:

@PersistenceContext 
private EntityManager entityManager; 


@PersistenceUnit 
private EntityManagerFactory entityManagerFactory; 

Pero cuando se utiliza la transacción y la entidad de soporte para gestor de primavera, que no es necesario el EntityManagerFactory en absoluto.

La razón por la que no necesita EntityManagerFactory es porque la creación del EntityManager es responsabilidad del administrador de transacciones. Esto es lo que ocurre en pocas palabras: gestor de

  • la transacción se dispara antes de que sus métodos
  • el administrador de transacciones recibe el EntityManagerFactory (que se inyecta en ella), crea un nuevo EntityManager, conjuntos en un ThreadLocal, y comienza una nueva transacción.
  • entonces los delegados al método de servicio
  • siempre que se encuentre @PersistenceContext, se inyecta un proxy (en su Dao), que, cada vez que accede, se pone la corriente EntityManager que se ha establecido en el ThreadLocal
+0

Aún necesita el EntityManager y Factory en los DAO, que es el único lugar donde existen en mi código. – Steve

+1

no, no es así. Por ejemplo, toda mi aplicación no tiene acceso a la fábrica en absoluto. EntityManager se inyecta en primavera, por lo que no es necesario utilizar la fábrica manualmente. – Bozho

+0

Derecha. Estamos haciendo lo mismo con los DAO (inyectando EntityManager). También estoy inyectando Factory (aunque actualmente no lo estoy usando para nada). Resulta que todo el problema fue un simple error de cortar y pegar. Estaba usando @PersistenceContext en EntityManagerFactory, en lugar de @PersistenceUnit. Una vez que cambié eso funcionó ... Gracias por el puntero ... – Steve

0

Tuve que hacer la combinación siguiente, además de agregar el bote de aspectos de primavera a las propiedades del proyecto-> Aspecto de ruta y habilitar aspectos de primavera en pts. Por supuesto, en mi archivo de configuración de contexto de aplicación, definí Entitymanagerfactory.

@ContextConfiguration (ubicaciones = { "/META-INF/spring/applicationContext-domain.xml"}) clase pública se extiende ReaderTest AbstractJUnit4SpringContextTests {

@PersistenceContext privada EntityManager entityManager;

0

Yo también tengo el mismo problema, cuando agregué el problema de java-persistencia api se resolvió.

<dependency> 
    <groupId>javax.persistence</groupId> 
    <artifactId>persistence-api</artifactId> 
    <version>1.0.2</version> 
</dependency> 
Cuestiones relacionadas