测试之@Sql(自动插入sql脚本,测试后销毁)

本文介绍了如何在Spring单元测试中使用@Sql注解加载SQL脚本,配合@Transactional注解实现数据的自动销毁,提高测试效率。通过例子展示了如何配置@SqlConfig和@SqlMergeMode。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

@Sql

@SqlConfig

@SqlMergeMode

@Transactional

案例

参考自:


前言

解决测试时测试数据写入与销毁不方便,使用@Sql自动导入sql脚本语句,结合@Transactional事务回滚实现测试后数据销毁,便捷测试。

@Sql

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

@Sql有下面的属性:

 config:配置@SqlConfig,它的作用域是其@Sql注释的本地范围。它用于配置commentPrefix、分隔符等。
 ​
 executionPhase:决定何时执行SQL脚本和语句。默认是BEFORE_TEST_METHOD。
 ​
 statements:配置执行内联SQL语句。
 ​
 scripts:配置SQL脚本执行的路径。
 ​
 value:脚本元素的别名。脚本和值不能一起使用,但可以与statement元素一起使用。

@SqlConfig

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

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

@SqlMergeMode

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

@Transactional

需要开启事务注解,这样测试中添加的数据会在测试后自动销毁,便于多次测试。

该注解需要在启动类处配置开启事务允许@EnableTransactionManagement

案例

sql:

 CREATE TABLE `user` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `username` varchar(50) DEFAULT NULL,
   `password` varchar(50) DEFAULT NULL,
   `name` varchar(50) DEFAULT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
 ​
 ​
 INSERT INTO `user` VALUES ('1', 'zhangsan', '123', '张三');
 INSERT INTO `user` VALUES ('2', 'lisi', '123', '李四');

测试时插入的脚本语句user.sql:

 insert into user values (3,"wangwu","12343","王五");

Controller:

 import java.util.List;
 ​
 @RestController
 public class UserController {
 ​
     @Autowired
     private UserService userService;
 ​
     @PostMapping("/hello")
     public List<UserEntity> getList(){
         return userService.list();
     }
 ​
 }

test(以验证@Sql与回滚功能为主):

 @RunWith(SpringRunner.class)
 @SpringBootTest
 @Transactional
 @AutoConfigureMockMvc
 @Sql(scripts = "/user.sql")
 //@SqlConfig(encoding = "UTF-8")
 class UserControllerTest {
 ​
     @Autowired
     MockMvc mockMvc;
 ​
     @Test
     void getList() throws Exception {
         MvcResult mvcResult = mockMvc.perform(post("/hello")).andReturn();
 ​
         MockHttpServletResponse response = mvcResult.getResponse();
         response.setCharacterEncoding("UTF-8");
         String JsonReturn = response.getContentAsString();
 ​
         // json转List
         List<UserEntity> userEntity = new ObjectMapper().readValue(JsonReturn,
                                                  new TypeReference<List<UserEntity>>(){});
         userEntity.forEach(System.out::println);
 ​
     }
 ​
 }

result:

 UserEntity(id=1, username=zhangsan, password=123, name=张三)
 UserEntity(id=2, username=lisi, password=123, name=李四)
 UserEntity(id=3, username=wangwu, password=12343, name=王五)

而数据库内不会出现新记录:

参考自:

Spring 单元测试中使用@Sql准备数据_xiegwei的博客-优快云博客_单元测试数据库数据准备

@Sql Example in Spring Test (concretepage.com)

推荐直接点进注解定义处看不同属性的注释说明。

英语基础较差推荐使用

  • 有道词典(划词翻译)

  • idea插件Translation

划词右键:

 

package com.bjsxt.servlet; import com.bjsxt.entity.User; import com.bjsxt.service.UserService; import com.bjsxt.service.impl.UserServiceImpl; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.*; import java.io.IOException; import java.net.URLEncoder; import java.sql.Date; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class UserServlet extends BaseServlet { // @Override // protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // //解决POST表单的中文乱码问题 // request.setCharacterEncoding("utf-8"); // //接收method属性的值 // String methodName = request.getParameter("method"); // // //根据method属性的值调用相应的方法 // if("login".equals(methodName)){ // this.login(request,response); // }else if("register".equals(methodName)){ // this.register(request,response); // }else if("logout".equals(methodName)){ // this.logout(request,response); // } // // } public void show(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取表单的数据 String userId = request.getParameter("userId"); if(userId == null){ userId = ""; } String strAge = request.getParameter("minAge"); int minAge = 0; try{ minAge = Integer.parseInt(strAge); //"12" "abc" }catch(NumberFormatException e){ e.printStackTrace(); } //调用业务层完成查询操作 UserService userService = new UserServiceImpl(); //List<User> userList = userService.findAll(); List<User> userList = userService.find(userId,minAge); //List<User> userList = null; //List<User> userList = new ArrayList<User>(); //跳转到show.jsp显示数据 request.setAttribute("userId",userId); request.setAttribute("minAge",strAge); request.setAttribute("ulist",userList); request.getRequestDispatcher("/admin/show.jsp").forward(request,response); } public void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //结束当前的session request.getSession().invalidate(); //跳转回登录页面 response.sendRedirect(request.getContextPath()+"/admin/login.jsp"); } public void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //request.setCharacterEncoding("utf-8"); //1.接收来自视图层的表单数据 String userId = request.getParameter("userId"); String realName = request.getParameter("realName"); String pwd = request.getParameter("pwd"); String rePwd = request.getParameter("repwd"); int age = Integer.parseInt(request.getParameter("age"));// "23" String [] hobbyArr = request.getParameterValues("hobby"); String strDate = request.getParameter("enterDate");//"1999-12-23" Date enterDate = Date.valueOf(strDate); //util.Date SimpleDateFormat //判断两次密码是否相同 if(pwd == null || !pwd.equals(rePwd)){ request.setAttribute("error","两次密码必须相同"); request.getRequestDispatcher("/admin/register.jsp").forward(request,response); return; } //2.调用业务层完成注册操作并返回结果 User user = new User(userId,realName,pwd,age, Arrays.toString(hobbyArr),enterDate); UserService userService = new UserServiceImpl(); int n = userService.register(user); //3.根据结果进行页面跳转 if(n>0){ response.sendRedirect(request.getContextPath()+"/admin/login.jsp"); }else{ request.setAttribute("error","注册失败"); request.getRequestDispatcher("/admin/register.jsp").forward(request,response); } } public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //解决POST表单的中文乱码问题 //request.setCharacterEncoding("utf-8"); //获取用户名和密码 request 内建对象 请求 String username = request.getParameter("username"); String password = request.getParameter("password"); String rememberme = request.getParameter("rememberme"); //调用下一层判断登录是否成功,并返回结果 //进行服务器端的表单验证 if(username ==null || "".equals(username)){ request.setAttribute("error","用户名不能为空JSP"); request.getRequestDispatcher("/admin/login.jsp").forward(request,response); return; } if (username.length()<=6){ request.setAttribute("error","用户名长度必须大于6JSP"); request.getRequestDispatcher("/admin/login.jsp").forward(request,response);//后面语句还会执行 return; //后面的语句不再执行 } // boolean flag = false;//默认失败 // if(username.indexOf("sxt")>=0 || username.contains("尚学堂")){ // flag = true; // } User user = null;//默认登录失败 // UserDao userDao = new UserDaoImpl(); // user = userDao.find(username,password); UserService userService = new UserServiceImpl(); user = userService.login(username,password); //userService.addOrder("shoppingCart"); //输出结果 if(user != null){ //登录成功才记住我 //1.办理会员卡 String username2 = URLEncoder.encode(username,"utf-8"); Cookie cookie1 = new Cookie("uname",username2); Cookie cookie2 = new Cookie("password",password); //2.指定会员卡的作用范围,默认范围是当前目录 /servlet/LoginServlet /admin/login.jsp //cookie1.setPath("/"); //当前服务器 cookie1.setPath("/myservlet2/"); //当前项目 cookie2.setPath("/myservlet2"); //3.指定会员卡的作用时间 if("yes".equals(rememberme)){ cookie1.setMaxAge(60*60*24*10); //默认的时间浏览器不关闭的时间;-1 表示一直有效 cookie2.setMaxAge(60*60*24*10); }else{ cookie1.setMaxAge(0); cookie2.setMaxAge(0); } //4.将会员卡带回家 response.addCookie(cookie1); response.addCookie(cookie2); //成功跳转到成功页面 //out.println("登录成功"); // /servlet/LoginServlet // /servlet/success.jsp // request.getRequestDispatcher("/admin/success.jsp").forward(request,response); HttpSession session = request.getSession(); // session.setAttribute("username",username); session.setAttribute("user",user); //response.sendRedirect("/myservlet2/admin/success.jsp"); //response.sendRedirect("https://www.bjsxt.com:443/news/11377.html"); //response.sendRedirect("http://localhost:8080/myservlet2/admin/success.jsp"); //response.sendRedirect("/myservlet2/admin/success.jsp"); //response.sendRedirect("/myservlet2/admin/success.jsp"); //response.sendRedirect(request.getContextPath()+"/admin/success.jsp"); //http://192.168.58.250:8080/myservlet2/servlet/LoginServlet //http://192.168.58.250:8080/myservlet2/admin/success.jsp //登录成功后,网站的访问人数+1 //1.获取当前的访问人数 ServletContext context = this.getServletContext(); Integer count2 = (Integer) context.getAttribute("count"); //2.人数+1 if(count2 == null){ //第一个用户 count2 = 1; }else{ count2++; } //3.再存放到application作用域中 context.setAttribute("count",count2); //http://192.168.58.250:8080/myservlet2/servlet/admin/success.jsp response.sendRedirect("../admin/success.jsp"); }else{ //失败跳转回登录页面 //out.println("登录失败"); request.setAttribute("error","用户名或者密码错误"); // RequestDispatcher rd = request.getRequestDispatcher("/admin/login.jsp"); // rd.forward(request,response); //RequestDispatcher rd = request.getRequestDispatcher("http://localhost:8080/myservlet2/admin/login.jsp"); //RequestDispatcher rd = request.getRequestDispatcher("/admin/login.jsp"); //http://192.168.58.250:8080/myservlet2/servlet/admin/login.jsp RequestDispatcher rd = request.getRequestDispatcher("../admin/login.jsp"); rd.forward(request,response); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值