【问题标题】:Unit testing, how to make spring management services do not pollute the database单元测试,如何让spring管理服务不污染数据库
【发布时间】:2017-11-03 17:07:19
【问题描述】:

我正在尝试使用spring和junit测试DAO的方法,我在网上看到的一些做法是使用spring语句式事务管理(@Transactional)进行业务操作,表示测试完成后,弹簧会让测试方法回滚,从而达到测试的目的。

然后我按照这种方式添加dao测试的方法的操作,发现事务提交,回滚不成功,数据库我出来了测试数据。一开始我以为是spring没有回滚,但是后面观察控制台打印信息发现有回滚信息,但是为什么会失败,不知道。我找到了一些相关的程序,但我发现并没有解决我的问题。很困扰,希望能得到您的帮助!

以下是我的代码和文件配置

  • DAOImpl的addUser()方法

    @Override
    public void addUser(User u) {
        Session session = sessionFactory.openSession();
        Transaction tc = session.getTransaction();
        try {
            tc.begin();
            session.save(u);
            tc.commit();
        }catch(Exception e){
            tc.rollback();
            e.printStackTrace();
        }
        return ;
    }
    
  • Daos.xml 文件配置

    <bean id="txManager"
    
        class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="txManager" />
    

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/services.xml"})
@Transactional(transactionManager = "txManager")
@Rollback(true)
 public class UserServiceImplTest {
    @Autowired
    UserDAO userDAO; 

    @Test
    public void testAddUse(){
        User u = new User();
        u.setLevel(3);
        u.setName("ab11");
        u.setPassword("hh");
        userDAO.addUser(u);
        Assert.assertEquals(u.getName(), userDAO.getUserList().get(userDAO.getUserList().size()-1).getName());
    }

一些控制台打印信息

INFO: Using DataSource [org.apache.commons.dbcp2.BasicDataSource@498d318c] of Hibernate SessionFactory for HibernateTransactionManager
    JUNE 02, 2017 4:46:19 afternoon org.springframework.test.context.transaction.TransactionContext startTransaction
INFO: Began transaction (1) for test context [DefaultTestContext@52d6cd34 testClass = UserServiceImplTest, testInstance = com.dxzh.mall.serviceImpl.test.UserServiceImplTest@715d6168, testMethod = testAddUse@UserServiceImplTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@75798d03 testClass = UserServiceImplTest, locations = '{classpath:/services.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.hibernate5.HibernateTransactionManager@c6634d]; rollback [true]
    Fri Jun 02 16:46:19 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
    Hibernate: insert into user (name, password, level) values (?, ?, ?)
    JUNE 02, 2017 4:46:19 afternoon org.springframework.test.context.transaction.TransactionContext endTransaction
INFO: Rolled back transaction for test context [DefaultTestContext@52d6cd34 testClass = UserServiceImplTest, testInstance = com.dxzh.mall.serviceImpl.test.UserServiceImplTest@715d6168, testMethod = testAddUse@UserServiceImplTest, testException = java.lang.RuntimeException, mergedContextConfiguration = [MergedContextConfiguration@75798d03 testClass = UserServiceImplTest, locations = '{classpath:/services.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
    JUNE 02, 2017 4:46:19 afternoon org.springframework.context.support.GenericApplicationContext doClose
INFO: Closing org.springframework.context.support.GenericApplicationContext@3ffc5af1: startup date [Fri Jun 02 16:46:13 CST 2017]; root of context hierarchy

【问题讨论】:

  • 记录一下:当一个测试涉及到一个数据库时,不要称它为一个单元测试。
  • @GhostCat 谢谢你的建议。但我仍然不知道如何使弹簧回滚。
  • 请放心:如果我有答案,我会给出的。这就是我在这里的原因。大多数时候。:-)

标签: java spring junit spring-transactions


【解决方案1】:

很遗憾,您在这里混合了两个概念。

您的生产代码直接管理事务,而您的测试代码使用 AOP(面向方面​​编程)spring 注释。

由于您的生产代码管理事务,因此您的测试代码中的 AOP 注释完全没用:事务巫婆规则是您生产代码中的规则。

解决方案:在您的生产代码中也使用 AOP。让健壮且经过良好测试的 Spring 事务机制来管理事务,而忘记自己管理它。像这样的:

@Override
@Transactional(transactionManager = "txManager")
public void addUser(User u) {
    // only your bussiness logic here
}

更多信息:here (example)here(Spring manal)


This wikipedia article 很好地解释了不同的软件测试方法。您的属于集成测试

类别

【讨论】:

  • 非常感谢,您的问题对我很有帮助。我找到了解决方案。因为我没有正确使用事务,所以回滚失败!我开始意识到: 1. 生产代码不应该是事务的管理; 2.应该使用getCurrentSession(),不应该使用openSession()。
  • 不客气。很高兴你学到了这一点。我学得很辛苦;)
猜你喜欢
  • 2019-10-15
  • 1970-01-01
  • 2011-10-08
  • 1970-01-01
  • 1970-01-01
  • 2013-02-13
  • 2016-02-17
  • 2013-03-04
  • 1970-01-01
相关资源
最近更新 更多