2010-03-24 8 views
9

Próbuję utworzyć testy JUnit dla moich klas JPA DAO, używając Spring 2.5.6 i JUnit 4.8.1.Zależność wtrysku ze sprężyną/Junit/JPA

Mój przypadek testowy wygląda następująco:


@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 ... 
} 

Mam następujących w moim 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> 

Teraz, gdy próbuję uruchomić to pojawia się następujący:

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 

Wydaje się, że mówię mi, że jego próba przechowania obiektu EntityManager w EntityManagerFactory fi ale nie rozumiem, jak i dlaczego. Moje klasy DAO akceptują zarówno EntityManager, jak i EntityManagerFactory za pomocą atrybutu @PersistenceContext i działają, jeśli je załaduję i uruchomię je bez atrybutu @ContextConfiguration (tzn. Jeśli użyję XmlApplcationContext do załadowania DAO i EntityManagerFactory bezpośrednio w setUp()).

Wszelkie spostrzeżenia będą mile widziane.

Odpowiedz

23

Są poprawne kombinacje adnotacji + interfejs:

@PersistenceContext 
private EntityManager entityManager; 


@PersistenceUnit 
private EntityManagerFactory entityManagerFactory; 

Jednak przy użyciu transakcji i jednostki wsparcia menedżera sprężyna w nie potrzebują EntityManagerFactory wcale.

Powodem, dla którego nie potrzebujesz EntityManagerFactory jest fakt, że utworzenie EntityManager należy do obowiązków menedżera transakcji. Oto co się dzieje w skrócie: menedżer

  • transakcja jest wyzwalany przed swoimi metodami
  • menedżer transakcji dostaje EntityManagerFactory (to jest wstrzykiwany w nim), tworzy nowy EntityManager, zestawy ww ThreadLocal, i rozpoczyna nową transakcję.
  • następnie deleguje do metody usługi
  • ilekroć @PersistenceContext napotkano, pełnomocnikiem jest wstrzykiwany (w DAO), który, gdy dostępne, dostaje aktualny EntityManager który został ustawiony w ThreadLocal
+0

Nadal potrzebujesz zarówno EntityManager, jak i Factory w DAO, który jest jedynym miejscem w moim kodzie. – Steve

+1

nie, nie. Na przykład moja cała aplikacja nie ma żadnego dostępu do fabryki. EntityManager jest wstrzykiwany wiosną, więc nie trzeba ręcznie używać fabryki. – Bozho

+0

Dobrze. Robimy to samo z DAO (wstrzykiwaniem EntityManager). Wstrzykuję również Fabrykę (chociaż obecnie nie używam jej do niczego). Okazuje się, że cały problem polegał na prostym wycięciu i wklejeniu. Używałem @PersistenceContext na EntityManagerFactory, a nie @PersistenceUnit. Raz zmieniłem, że to zadziałało ... Dzięki za wskazówkę ... – Steve

0

Musiałem wykonać poniższą kombinację, poza dodaniem słoików z aspektami sprężynowymi do właściwości projektu -> Aspect Path i umożliwienia wiosennych aspektów w st. Oczywiście w moim pliku konfiguracyjnym kontekstu aplikacji zdefiniowałem Entitymanagerfactory.

@ContextConfiguration (lokalizacje = { "/META-INF/spring/applicationContext-domain.xml"}) public class ReaderTest rozciąga AbstractJUnit4SpringContextTests {

@PersistenceContext private EntityManager EntityManager;

0

Ja też mam ten sam problem, kiedy dodałem problem z utrzymaniem java, problem został rozwiązany.

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