2010-03-24 42 views
9

Tôi đang cố tạo các bài kiểm tra JUnit cho các lớp JPA DAO của mình, sử dụng Spring 2.5.6 và JUnit 4.8.1.Tiêm phụ thuộc với Spring/Junit/JPA

trường hợp thử nghiệm của tôi trông như thế này:


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

Tôi đã sau trong jpaDaoTestsConfig.xml tôi:


<?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> 

Bây giờ, khi tôi cố gắng chạy này, tôi nhận được như sau:

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 

Dường như đang nói với tôi rằng nỗ lực lưu trữ đối tượng EntityManager vào fi EntityManagerFactory nhưng tôi không hiểu tại sao. Các lớp DAO của tôi chấp nhận cả EntityManager và EntityManagerFactory thông qua thuộc tính @PersistenceContext và chúng hoạt động tìm thấy nếu tôi tải chúng lên và chạy chúng mà không có thuộc tính @ContextConfiguration (tức là nếu tôi chỉ sử dụng XmlApplcationContext để tải DAO và EntityManagerFactory trực tiếp trong thiết lập()).

Mọi thông tin chi tiết sẽ được đánh giá cao.

Trả lời

23

Đây là sự kết hợp đúng đắn về chú thích + giao diện:

@PersistenceContext 
private EntityManager entityManager; 


@PersistenceUnit 
private EntityManagerFactory entityManagerFactory; 

Nhưng khi sử dụng giao dịch và tổ chức hỗ trợ quản lý mùa xuân, bạn không cần EntityManagerFactory ở tất cả.

Lý do bạn không cần EntityManagerFactory là do việc tạo EntityManager là trách nhiệm của người quản lý giao dịch. Dưới đây là những gì xảy ra trong ngắn hạn: quản lý

  • giao dịch được kích hoạt trước khi phương pháp của bạn
  • người quản lý giao dịch nhận được EntityManagerFactory (nó được tiêm vào nó), tạo ra một mới EntityManager, bộ ở trong một ThreadLocal, và bắt đầu giao dịch mới.
  • sau đó nó đại biểu cho phương thức dịch vụ
  • bất cứ khi nào @PersistenceContext đang gặp phải, một proxy được tiêm (trong Đạo của bạn), trong đó, bất cứ khi nào truy cập, được dòng điện EntityManager đã được thiết lập trong ThreadLocal
+0

Bạn vẫn cần cả EntityManager và Factory trong DAO, đây là nơi duy nhất chúng tồn tại trong mã của tôi. – Steve

+1

không, bạn không. Ví dụ: toàn bộ ứng dụng của tôi không có quyền truy cập vào nhà máy nào. EntityManager được tiêm vào mùa xuân, vì vậy không cần phải sử dụng nhà máy một cách thủ công. – Bozho

+0

Phải. Chúng tôi đang làm điều tương tự với DAO (tiêm EntityManager). Tôi cũng đang tiêm Nhà máy (mặc dù hiện tại tôi không sử dụng nó). Nó chỉ ra rằng toàn bộ vấn đề là một lỗi cắt và dán đơn giản. Tôi đã sử dụng @PersistenceContext trên EntityManagerFactory, chứ không phải là @PersistenceUnit. Một khi tôi thay đổi nó làm việc ... Cảm ơn con trỏ ... – Steve

0

Tôi đã phải thực hiện sự kết hợp dưới đây, ngoài việc thêm vào các bình xuân vào các thuộc tính của dự án-> Aspect Path và cho phép các khía cạnh mùa xuân trong các sts. Ofcourse trong tập tin cấu hình ngữ cảnh ứng dụng của tôi, tôi đã định nghĩa Entitymanagerfactory.

@ContextConfiguration (địa điểm = { "/META-INF/spring/applicationContext-domain.xml"}) public class ReaderTest kéo dài AbstractJUnit4SpringContextTests {

@PersistenceContext tin EntityManager EntityManager;

0

Tôi cũng gặp vấn đề tương tự, Khi tôi thêm sự cố api java-persistence đã được giải quyết.

<dependency> 
    <groupId>javax.persistence</groupId> 
    <artifactId>persistence-api</artifactId> 
    <version>1.0.2</version> 
</dependency> 
Các vấn đề liên quan