事务教程——测试回滚

Posted

技术标签:

【中文标题】事务教程——测试回滚【英文标题】:transaction tutorial - test rollback 【发布时间】:2014-07-01 08:07:06 【问题描述】:

我正在尝试学习如何在 java spring 中使用事务。我是一个java新手,所以请多多包涵:-) 我试图在下面实现的单元测试是测试: 如果抛出运行时异常,则回滚。

我遇到的问题是 java.lang.NullPointerException?

好的。我已经删除了一些代码以帮助提高可读性

TutorialTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class, loader=AnnotationConfigContextLoader.class)
public class TutorialTest 

    @Autowired
    private Dao dao;


    @Test
    public void that_if_a_runtime_exception_is_thrown_transaction_rolledback()

        User u = new User();
        u.setUsername("FAIL_TEST");
        u.setPhone("0161");
        u.setEmail("FAIL_TEST@gmail.com");
        //dao.addUser(u);  // -- this will insert if uncommented out so I know it works

        OuterService os  = new OuterService();
        os.addUserThrowError(u);

    

OuterService.java

@ContextConfiguration(classes = AppConfig.class, loader=AnnotationConfigContextLoader.class)
public class OuterService 

    @Autowired
    private Dao dao;

    @Transactional
    public void addUserThrowError(User user) throws RuntimeException

        dao.addUser(user);  // gives me a java.lang.NullPointerException?

        throw new RuntimeException("This should roll back DB entry");
    


Bean 在

中声明

AppConfig.java

@Configuration
@EnableTransactionManagement
@ComponentScan(value = "com.training.spring.tx.tutorial.dao",
                        "com.training.spring.tx.tutorial.service")
public class AppConfig 

    public DataSource dataSource() 

        // Create a BasicDataSource object and configure database

        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost/spring_training_tx");
        dataSource.setUsername("training");
        dataSource.setPassword("training");

        return dataSource;
    

    @Bean
    public DataSourceTransactionManager transactionManager() 
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        return transactionManager;
    

    @Bean
    public JdbcTemplate jdbcTemplate()
        return new JdbcTemplate(transactionManager().getDataSource());
    


【问题讨论】:

Spring不参与new OuterService(); 查看 Javadoc。 Spring 有非常好的文档。 @ContextConfiguration 是做什么的? Spring中如何声明bean? 嗨,我已经更新了问题以帮助改进它。我还从标题中删除了 spring。我已经包含了 beans 声明。 答案非常简单:Spring 不涉及 new OuterService();,因此不会将任何东西自动装配到该对象中。解释比较长。阅读 Spring IoC 文档,其中解释了所有这些。 我已经查看了文档,但我并没有更接近于弄清楚我需要做什么?根据您的回复,我认为我需要将 new OuterService() 与 beans 配置链接。上面的 bean 示例在 XML 中,而我被告知要学习的不是.. 【参考方案1】:

首先,引用javadoc of @ContextConfiguration

@ContextConfiguration 定义了类级元数据,用于 确定如何加载和配置ApplicationContext 集成测试。

考虑您在OuterService 上的使用方式。看起来对吗? OuterService 是否用于加载和配置 ApplicationCOntext 以进行集成测试?除非我遗漏了一些重要的东西,否则答案是:不。

那么OuterService 是什么?这是某种服务。您似乎想将其用作 bean。什么是豆子? bean 是一个对象,其生命周期由 Spring 管理。这包括 bean 类的实例化、对象的初始化、后处理,最后是对象的销毁。

如果你这样创建对象

OuterService os  = new OuterService();

则不涉及 Spring。您创建了对象,Spring 无法与之挂钩。因此,您不能期望 Spring 自动装配其字段

@Autowired
private Dao dao;

由于您还没有初始化该字段,它仍然是null,这会导致NullPointerException

那么我们如何获得一个OuterService bean, 由 Spring 管理?您可以为OuterService 声明@Bean 方法,或者使用@Component 或其任何特化注释OuterService,然后对它所在的包进行组件扫描。然后将bean 注入使用它的任何其他bean。例如,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class, loader=AnnotationConfigContextLoader.class)
public class TutorialTest 

    @Autowired
    private Dao dao;

    @Autowired
    private OuterService os;

然后您可以直接使用该变量。

【讨论】:

以上是关于事务教程——测试回滚的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 测试不会在每次测试后回滚事务

Spring boot,测试后事务不回滚

junit测试事务回滚时遇到的问题

SpringBoot实现单元测试时回滚事务

SpringBoot实现单元测试时回滚事务

spring测试事务回滚,抛出RuntimeException