Spring 单元测试中使用@Sql准备数据

在写单元测试时,往往需要在数据库中准备对应的测试数据。
我们可以在测试用例中,通过代码的方式往数据库中插入数据。但这么做会使测试代码比较臃肿。
个人觉得,通过sql脚本去导入数据,再结合@Transactional注解对数据进行回滚,是一种更好的方案。
为此,spring为我们准备了很有用的注解@Sql。

@Sql

@Sql注解可以执行SQL脚本,也可以执行SQL语句。它既可以加上类上面,也可以加在方法上面。
默认情况下,方法上的@Sql注解会覆盖类上的@Sql注解,但可以通过@SqlMergeMode注解来修改此默认行为。
@Sql有下面的属性:

  • config:与注解@SqlConfig作用一样,用来配置“注释前缀”,“分隔符”等。
  • executionPhase:决定SQL脚本或语句什么时候会执行,默认是BEFORE_TEST_METHOD。
  • statements:配置要一起执行的SQL语句。
  • scripts:配置SQL脚本路径。
  • value:scripts的别名,它不能和scripts同时配置,但statements可以。

例如:

@Sql({ "/drop_schema.sql", "/create_schema.sql" })
@Sql(scripts = "/insert_data1.sql", statements = "insert into student(id, name) values (100, 'Shiva')")
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfig.class)
public class SqlTest {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Test
	public void fetchRows1() {
		List<Map<String, Object>> students = jdbcTemplate.queryForList("SELECT * FROM student");
		assertEquals(3, students.size());
	}

	@Sql("/insert_more_data1.sql")
	@Test
	public void fetchRows2() {
		List<Map<String, Object>> students = jdbcTemplate.queryForList("SELECT * FROM student");
		assertEquals(5, students.size());
	}
} 

drop_schema.sql :

drop table if exists student; 

create_schema.sql :

CREATE TABLE student (
  id INT NOT NULL,
  name VARCHAR(50) NOT NULL,
  PRIMARY KEY(id)
); 

insert_data1.sql :

insert into student(id, name) values (101, 'Mohan');
insert into student(id, name) values (102, 'Krishna'); 

insert_more_data1.sql :

insert into student(id, name) values (103, 'Indra');
insert into student(id, name) values (104, 'Chandra'); 

@SqlConfig

@SqlConfig用于配置如何去解释@Sql注解中指定的Sql脚本。
@SqlConfig可以用于类上,也可以用于方法上。
@Sql注解也有一个config属性,作用与@SqlConfig相同,不同的是作用域只在对应的@Sql注解范围。它的优先级也大于类注解的@SqlConfig。

  • blockCommentStartDelimiter:多行注释开始字符,默认是/*。
  • blockCommentEndDelimiter:多行注释结束字符,默认是*/。
  • commentPrefix:单行注释前缀,默认是–。
  • commentPrefixes:指定多个单行注释前缀,默认是["–"]。
  • dataSource:指定脚本执行的数据库的名字,只有在多个数据源时需要指定。
  • encoding:指定sql脚本文件的字符编码。
  • errorMode:配置错误模式,默认是SqlConfig.ErrorModeDEFAULT
  • separator:配置脚本语句分隔符,默认是’\n’。
  • transactionManager:指定transactionManager bean,只有有多个transactionManager时需要指定。
  • transactionMode:指定脚本执行的事务模式,默认是SqlConfig.TransactionModeDEFAULT

例子:

@SqlConfig(commentPrefix = "#")
@Sql({ "/drop_schema.sql", "/create_schema.sql" })
@Sql(scripts = { "/insert_data2.sql" })
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfig.class)
public class SqlConfigTest {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Test
	public void fetchRows1() {
		List<Map<String, Object>> students = jdbcTemplate.queryForList("SELECT * FROM student");
		assertEquals(2, students.size());
	}

	@Sql(scripts = "/insert_more_data2.sql", config= @SqlConfig(commentPrefix = "~"))
	@Test
	public void fetchRows2() {
		List<Map<String, Object>> students = jdbcTemplate.queryForList("SELECT * FROM student");
		assertEquals(4, students.size());
	}
} 

insert_data2.sql :

#Insert initial data

insert into student(id, name) values (101, 'Mohan');
insert into student(id, name) values (102, 'Krishna'); 

@SqlMergeMode

@SqlMergeMode可以加在类上,也可以加在方法上。用于指示方法上的@Sql和类上@Sql注解配置是否合并。方法上的@SqlMergeMode注解优先级更高。默认值是SqlMergeMode.MergeModeOVERRIDE

例:

@SqlMergeMode(MergeMode.MERGE)
@Sql({ "/drop_schema.sql", "/create_schema.sql", "/insert_data1.sql" })
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfig.class)
public class SqlMergeModeTest {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Sql(statements = "insert into student(id, name) values (100, 'Shiva')")	
	@Test
	public void fetchRows1() {
		List<Map<String, Object>> students = jdbcTemplate.queryForList("SELECT * FROM student");
		assertEquals(3, students.size());
	}

	@SqlMergeMode(MergeMode.OVERRIDE)	
	@Sql("/insert_more_data1.sql")
	@Test
	public void fetchRows2() {
		List<Map<String, Object>> students = jdbcTemplate.queryForList("SELECT * FROM student");
		assertEquals(5, students.size());
	}
} 
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot 项目的单元测试通常使用 JUnit 和 Spring Test 模块。下面是一个简单的 Spring Boot 单元测试示例代码: ```java import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringJUnitConfig @SpringBootTest @AutoConfigureMockMvc @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @DataJpaTest public class UserControllerTest { @Autowired private MockMvc mockMvc; @Test @Sql(scripts = "/data.sql", config = @SqlConfig(encoding = "UTF-8")) public void getUserByIdTest() throws Exception { MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/users/1")) .andExpect(status().isOk()) .andReturn(); String content = result.getResponse().getContentAsString(); assertEquals("{\"id\":1,\"name\":\"John\",\"age\":30}", content); } } ``` 上面的示例代码演示了如何编写一个测试 `UserController` 的单元测试。在 Spring Boot ,我们通常使用 `@SpringBootTest` 注解来启动整个应用程序上下文,使用 `@AutoConfigureMockMvc` 注解来注入 MockMvc 对象,以便测试控制器的 RESTful API。我们还可以使用 `@DataJpaTest` 注解和 `@AutoConfigureTestDatabase` 注解来配置测试数据库,以便测试持久化操作。在这个例子,我们还使用了 `@Sql` 注解来执行 SQL 脚本,以便在测试准备测试数据。 总的来说,Spring Boot 的单元测试相比传统的单元测试更加复杂,但是也更加强大和灵活。我们可以根据具体的测试需求来选择合适的测试工具和策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiegwei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值