2012-04-04 52 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類按照預期行事,向數據庫寫入數據和從數據庫讀取數據,並且在服務層上,您可以避免測試此方面,更多地關注業務邏輯的「模擬」方法。

希望它可以幫助

弗蘭