2012-04-04 80 views
2

我有以下的测试案例:无法测试JPA +春

@ContextConfiguration("/spring/test-context.xml") 
@TransactionConfiguration(transactionManager="txManager") 
@Transactional() 
public class MyEntityDaoTestCase extends AbstractJUnit4SpringContextTests { 

    @Autowired 
    private MyEntityDao dao; 

    @Test 
    public void testSave_success() { 
     MyEntity e = new MyEntity(); 
     dao.save(e); 
     MyEntity result = dao.findById(e.getId()); 
     assertNotNull(result);  
    } 
} 

吾道定义已经如下:

public abstract class MyEntityDAO { 

    @PersistenceContext 
    private EntityManager mEntityManager; 

    public void save(MyEntity entity) { 
     mEntityManager.persist(entity); 
    } 

    public MyEntity findById(Long id) { 
     return mEntityManager.find(mEntityClass, id); 
    } 
} 

我的Spring配置如下:

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

    <!-- 
     Bean post-processor for JPA annotations 
    --> 
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> 

    <!-- 
     JPA entity manager factory 
    --> 
    <bean id="jpaEntityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="unit-test-pu"/> 
    </bean> 

    <!-- 
     Transaction manager 
    --> 
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="jpaEntityManagerFactory"/> 
    </bean> 

    <!-- 
     Enable the configuration of transactional behavior based on annotations 
    --> 
    <tx:annotation-driven transaction-manager="txManager"/> 

    <!-- 
     DAO instance beans 
    --> 
    <bean id="mockEntityDao" class="mypackage.MyEntityDao"></bean> 

</beans> 

我在执行测试时没有遇到任何错误,但它不会通过。它看起来像findById()方法不会在数据库中找到实体。任何人都可以建议如何正确测试这种情况?

编辑:

我的JPA提供程序是休眠。我使用的是内存中的HSQLDB为我的单元测试,并具有以下配置:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
      version="2.0"> 
    <persistence-unit name="unit-test-pu" transaction-type="RESOURCE_LOCAL"> 
     <properties> 
     <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/> 
     <property name="javax.persistence.jdbc.user" value="sa"/> 
     <property name="javax.persistence.jdbc.password" value=""/> 
     <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:."/> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> 
     <property name="hibernate.archive.autodetection" value="class"/> 
     <property name="hibernate.show_sql" value="true"/> 
     <property name="hibernate.format_sql" value="true"/> 
     <property name="hibernate.hbm2ddl.auto" value="create"/> 
     </properties>  
    </persistence-unit> 
</persistence> 
+0

什么是JPA的供应商和配置? – mguymon 2012-04-04 12:30:58

+0

我正在使用休眠。我在我的文章中添加了我的配置。 – 2012-04-04 12:41:35

+0

MyEntity被正确保存,因此e.getId()的id不为空? – mguymon 2012-04-04 12:52:11

回答

0

如果你严格遵守TDD,你不应该使用内存数据库,而应该让所有的东西都被嘲笑。问题是persist方法返回void。所以,你不能测试正确的响应(通过数据库生成ID的实体)来解决的方法之一是给我们的Mockito doAnswer方法,这里一个例子:

@RunWith(MockitoJUnitRunner.class) 
public class CookieRepositoryTest { 

@Mock 
EntityManager em; 

@Mock 
TimeService timeService; 

@InjectMocks 
CookieRepository underTest = new CookieRepository(); 

@Test 
public void testCreateEntity() throws Exception { 
Cookie newCookie = new Cookie(); 

when(timeService.getTime()).thenReturn(new DateTime(DateTimeZone.UTC)); 

doAnswer(new Answer<Brand>() { 
@Override 
public Brand answer(InvocationOnMock invocationOnMock) throws Throwable { 
Object[] args = invocationOnMock.getArguments(); 
Cookie cookie = (Cookie) args[0]; 
cookie.setId(1); 
return null; 
} 

}).when(em).persist(any(Brand.class)); 

Cookie persistedCookie = underTest.createEntity(newCookie); 
assertNotNull(persistedCookie.getId()); 
} 

} 

一个完整的解释可以发现在我的博客post

2

你可以尝试使用@TransactionalConfiguration注释和Spring的JUnit运行。

事情是改变你的类此:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/spring/test-context.xml") 
@TransactionConfiguration(transactionManager="txManager", defaultRollback=true) 
@Transactional 
public class MyEntityDaoTestCase { 

这也意味着你不需要扩展抽象的情况下(因为你使用的是Spring亚军) - 除非你特别喜欢这种做法。

这里更details

+0

我试过设置defaultRollback = true。它不起作用。 – 2012-04-04 13:13:06

+0

只是一个评论:请不要使用defaultRollback设置为true! Hibernate将insert/update语句保留在内存中,直到它们被刷新到数据库(通过选择或显式刷新)。因此,Hibernate可能在您的测试中永远不会碰到数据库,这意味着您在部署应用程序时仍然可能会出错,尽管您有测试*。 – Augusto 2012-04-04 13:43:35

+0

这就是我的问题。我'想冬眠冲洗为了测试我的情况。看看我的测试方法,你会明白我的意思...... – 2012-04-04 14:03:15

0

如果要测试持久层,还可以查看DBUnit功能。

你可以找到彼得Kainulainen一个很好的文章在这里大约在Spring基于场景的测试持久层(在这种情况下使用JPA):

http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-integration-testing/

有了这个,你测试是否DAO类按照预期行事,向数据库写入数据和从数据库读取数据,并且在服务层上,您可以避免测试此方面,更多地关注业务逻辑的“模拟”方法。

希望它可以帮助

弗兰