Spring4.1新特性——数据库集成测试

简介: <p>在Spring 4.1之前我们在准备测试数据时可能通过继承AbstractTransactionalJUnit4SpringContextTests,然后调用executeSqlScript()进行测试,其中存在一个主要问题:如果要同时执行多个数据源的初始化就靠不住了,而且使用起来也不是特别便利,Spring4.1提供了@Sql注解来完成这个任务。</p> <p> </p> <p

在Spring 4.1之前我们在准备测试数据时可能通过继承AbstractTransactionalJUnit4SpringContextTests,然后调用executeSqlScript()进行测试,其中存在一个主要问题:如果要同时执行多个数据源的初始化就靠不住了,而且使用起来也不是特别便利,Spring4.1提供了@Sql注解来完成这个任务。

 

1、初始化Spring配置: 

Java代码   收藏代码
  1. <jdbc:embedded-database id="dataSource1" type="HSQL"/>  
  2. <jdbc:embedded-database id="dataSource2" type="HSQL"/>  
  3.   
  4. <bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  5.     <property name="dataSource" ref="dataSource1"/>  
  6. </bean>  
  7.   
  8. <bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  9.     <property name="dataSource" ref="dataSource2"/>  
  10. </bean>  

此处使用jdbc:embedded嵌入数据库来完成测试,数据库使用HSQL。

 

2、 方法级别的@Sql

Java代码   收藏代码
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  5. public class MethodLevelSqlTest {  
  6.     private JdbcTemplate jdbcTemplate1;  
  7.     private JdbcTemplate jdbcTemplate2;  
  8.     @Autowired  
  9.     @Qualifier("dataSource1")  
  10.     public void setDataSource1(DataSource dataSource1) {  
  11.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  12.     }  
  13.     @Autowired  
  14.     @Qualifier("dataSource2")  
  15.     public void setDataSource2(DataSource dataSource2) {  
  16.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  17.     }  
  18.   
  19.   
  20.     @Test  
  21.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  22.             config =  
  23.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  24.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  25.     public void test01_simple() {  
  26.         Assert.assertEquals(  
  27.                 Integer.valueOf(3),  
  28.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  29.     }  
  30.   
  31.   
  32.     @Test  
  33.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  34.             config =  
  35.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  36.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  37.     public void test02_simple() {  
  38.         Assert.assertEquals(  
  39.                 Integer.valueOf(2),  
  40.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  41.     }  
  42.   
  43. }  

方法级别的@Sql在每个方法上都会执行。其中@Sql可以指定多个sql文件,然后通过@SqlConfig指定其编码、分隔符、注释前缀、使用哪个数据源和事务管理器。

 

 

3、类级别的@Sql

Java代码   收藏代码
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  5.         config =  
  6.         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  7.                 dataSource = "dataSource1", transactionManager = "txManager1"))  
  8. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  9. public class ClassLevelSqlTest {  
  10.   
  11.     private JdbcTemplate jdbcTemplate1;  
  12.     @Autowired  
  13.     @Qualifier("dataSource1")  
  14.     public void setDataSource1(DataSource dataSource1) {  
  15.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  16.     }  
  17.   
  18.     @Test  
  19.     public void test01_simple() {  
  20.         Assert.assertEquals(  
  21.                 Integer.valueOf(3),  
  22.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  23.     }  
  24. }  

类级别的对整个测试用例中的每个方法都起作用。 

 

4、指定多个@Sql 

Java8之前需要使用@SqlGroup,而Java8之后直接使用多个@Sql注解即可。

Java代码   收藏代码
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @Transactional()  
  5. @SqlGroup(  
  6.         {  
  7.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  8.                         config =  
  9.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  10.                                 dataSource = "dataSource1", transactionManager = "txManager1")),  
  11.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  12.                         config =  
  13.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  14.                                 dataSource = "dataSource2", transactionManager = "txManager2"))  
  15.         }  
  16. )  
  17.   
  18. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  19. public class ClassLevelSqlGroupTest {  
  20.   
  21.     private JdbcTemplate jdbcTemplate1;  
  22.     private JdbcTemplate jdbcTemplate2;  
  23.     @Autowired  
  24.     @Qualifier("dataSource1")  
  25.     public void setDataSource1(DataSource dataSource1) {  
  26.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  27.     }  
  28.     @Autowired  
  29.     @Qualifier("dataSource2")  
  30.     public void setDataSource2(DataSource dataSource2) {  
  31.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  32.     }  
  33.   
  34.   
  35.     @Test  
  36.     @Transactional()  
  37.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  38.             config =  
  39.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  40.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  41.     public void test01_simple() {  
  42.         Assert.assertEquals(  
  43.                 Integer.valueOf(3),  
  44.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  45.     }  
  46.   
  47.   
  48.     @Test  
  49.     @Transactional()  
  50.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  51.             config =  
  52.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  53.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  54.     public void test02_simple() {  
  55.         Assert.assertEquals(  
  56.                 Integer.valueOf(2),  
  57.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  58.     }  
  59.   
  60. }  

 

也可以通过元注解把注解合并:

Java代码   收藏代码
  1. @SqlGroup(  
  2.         {  
  3.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  4.                         config =  
  5.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  6.                                 dataSource = "dataSource1", transactionManager = "txManager1")),  
  7.                 @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  8.                         config =  
  9.                         @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  10.                                 dataSource = "dataSource2", transactionManager = "txManager2"))  
  11.         }  
  12. )  
  13. @Retention(RUNTIME)  
  14. @Target(TYPE)  
  15. @interface CompositeSqlGroup {  
  16. }  

直接使用@CompositeSqlGroup注解即可。

 

5、事务

Java代码   收藏代码
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)  
  3. @ContextConfiguration(value = "classpath:spring-datasource.xml")  
  4. @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)  
  5. public class TransactionalTest {  
  6.     private JdbcTemplate jdbcTemplate1;  
  7.     private JdbcTemplate jdbcTemplate2;  
  8.     @Autowired  
  9.     @Qualifier("dataSource1")  
  10.     public void setDataSource1(DataSource dataSource1) {  
  11.         this.jdbcTemplate1 = new JdbcTemplate(dataSource1);  
  12.     }  
  13.     @Autowired  
  14.     @Qualifier("dataSource2")  
  15.     public void setDataSource2(DataSource dataSource2) {  
  16.         this.jdbcTemplate2 = new JdbcTemplate(dataSource2);  
  17.     }  
  18.   
  19.   
  20.     @Test  
  21.     @Transactional("txManager1")  
  22.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql""classpath:updated-data.sql"},  
  23.             config =  
  24.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  25.                     dataSource = "dataSource1", transactionManager = "txManager1"))  
  26.     public void test01_simple() {  
  27.         //判断是在事务中执行  
  28.         Assert.assertTrue(TransactionSynchronizationManager.isActualTransactionActive());  
  29.         Assert.assertTrue(TestTransaction.isActive());  
  30.         Assert.assertEquals(  
  31.                 Integer.valueOf(3),  
  32.                 jdbcTemplate1.queryForObject("select count(1) from users", Integer.class));  
  33.     }  
  34.   
  35.   
  36.     @Test  
  37.     @Transactional("txManager2")  
  38.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  39.             config =  
  40.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  41.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  42.     public void test02_simple() {  
  43.         Assert.assertEquals(  
  44.                 Integer.valueOf(2),  
  45.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  46.     }  
  47.   
  48.   
  49.     @Test  
  50.     @Transactional("txManager2")  
  51.     @Sql(value = {"classpath:schema.sql""classpath:init-data.sql"},  
  52.             config =  
  53.             @SqlConfig(encoding = "utf-8", separator = ";", commentPrefix = "--",  
  54.                     dataSource = "dataSource2", transactionManager = "txManager2"))  
  55.     public void test03_simple() {  
  56.         Assert.assertEquals(  
  57.                 Integer.valueOf(2),  
  58.                 jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  59.         TestTransaction.flagForRollback();  
  60.     }  
  61.   
  62.     @Rule  
  63.     public TestName testName = new TestName();  
  64.     @AfterTransaction  
  65.     public void afterTransaction() {  
  66.         System.out.println(testName.getMethodName());  
  67.         if("test03_simple".equals(testName.getMethodName())) {  
  68.             Assert.assertEquals(  
  69.                     Integer.valueOf(0),  
  70.                     jdbcTemplate2.queryForObject("select count(1) from users", Integer.class));  
  71.         }  
  72.     }  
  73. }  

可以使用//判断是在事务中执行TransactionSynchronizationManager.isActualTransactionActive()或TestTransaction.isActive()来判断是否是在事务中执行;通过TestTransaction.flagForRollback();来回滚事务;在测试用例中@AfterTransaction来断言回滚后数据没有插入。


本文转自http://jinnianshilongnian.iteye.com/blog/2106184

目录
相关文章
|
3月前
|
数据可视化 Java BI
将 Spring 微服务与 BI 工具集成:最佳实践
本文探讨了 Spring 微服务与商业智能(BI)工具集成的潜力与实践。随着微服务架构和数据分析需求的增长,Spring Boot 和 Spring Cloud 提供了构建可扩展、弹性服务的框架,而 BI 工具则增强了数据可视化与实时分析能力。文章介绍了 Spring 微服务的核心概念、BI 工具在企业中的作用,并深入分析了两者集成带来的优势,如实时数据处理、个性化报告、数据聚合与安全保障。同时,文中还总结了集成过程中的最佳实践,包括事件驱动架构、集中配置管理、数据安全控制、模块化设计与持续优化策略,旨在帮助企业构建高效、智能的数据驱动系统。
223 1
将 Spring 微服务与 BI 工具集成:最佳实践
|
5月前
|
XML 人工智能 Java
Spring Boot集成Aviator实现参数校验
Aviator是一个高性能、轻量级的Java表达式求值引擎,适用于动态表达式计算。其特点包括支持多种运算符、函数调用、正则匹配、自动类型转换及嵌套变量访问,性能优异且依赖小。适用于规则引擎、公式计算和动态脚本控制等场景。本文介绍了如何结合Aviator与AOP实现参数校验,并附有代码示例和仓库链接。
366 0
|
5月前
|
安全 Java 数据库
第16课:Spring Boot中集成 Shiro
第16课:Spring Boot中集成 Shiro
814 0
|
5月前
|
消息中间件 存储 Java
第15课: Spring Boot中集成ActiveMQ
第15课: Spring Boot中集成ActiveMQ
495 0
|
2月前
|
安全 Java 测试技术
《深入理解Spring》单元测试——高质量代码的守护神
Spring测试框架提供全面的单元与集成测试支持,通过`@SpringBootTest`、`@WebMvcTest`等注解实现分层测试,结合Mockito、Testcontainers和Jacoco,保障代码质量,提升开发效率与系统稳定性。
|
6月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
723 0
|
3月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
628 5
|
9月前
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
498 0
|
3月前
|
监控 Cloud Native Java
Spring Integration 企业集成模式技术详解与实践指南
本文档全面介绍 Spring Integration 框架的核心概念、架构设计和实际应用。作为 Spring 生态系统中的企业集成解决方案,Spring Integration 基于著名的 Enterprise Integration Patterns(EIP)提供了轻量级的消息驱动架构。本文将深入探讨其消息通道、端点、过滤器、转换器等核心组件,以及如何构建可靠的企业集成解决方案。
361 0