2

我有以下测试用例:

@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);      
    }
}

我的 DAO 定义如下:

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

4 回答 4

2

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

比如把你的班级改成这样:

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

这也意味着您不需要扩展抽象案例(因为您使用的是 Spring 运行器)——除非您特别喜欢这种方法。

这里有更多细节

于 2012-04-04T12:53:03.390 回答
0

我认为您应该扩展AbstractTransactionalJUnit4SpringContextTests而不是 AbstractJUnit4SpringContextTests 以使@Transactional-annotations 产生任何效果。

于 2012-04-04T13:42:52.977 回答
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());
 }

}

完整的解释可以在我的博客文章中找到。

于 2012-07-02T16:34:57.537 回答
0

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

您可以在此处找到来自 Petri Kainulainen 的一篇关于在基于 Spring 的场景中测试持久层(在本例中为 JPA)的好文章:

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

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

希望能帮助到你

弗兰

于 2014-12-26T19:31:58.043 回答