spring boot单元测试之四:单元测试中测试文件上传(spring boot 2.4.3)
一,演示项目的相关信息
1,地址:
https://github.com/liuhongdi/fileuptest
2,功能说明:演示了在单元测试中如何测试文件上传
3,项目结构:如图:
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/26/spring-boot-dan-yuan-ce-shi-zhi-si-dan-yuan-ce-shi-zhong-ce/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,配置文件说明
1,application.yml
#thymeleaf spring: thymeleaf: cache: false encoding: UTF-8 mode: HTML prefix: classpath:/templates/ suffix: .html #upload servlet: multipart: maxFileSize: 10MB maxRequestSize: 30MB #tomcat, server: tomcat: connection-timeout: 20000 max-http-form-post-size: 30MB #error error: include-stacktrace: always #errorlog logging: level: org.springframework.web: trace
三,java代码说明
1,controller/FileController.java
@Controller @RequestMapping("/file") public class FileController { //文件的保存路径 private final static String FILE_BASE_PATH = "/data/file/html"; //单文件/多文件上传页面 @GetMapping("/upload") public String upload(ModelMap modelMap) { return "image/upload"; } //处理单文件/多文件上传 @PostMapping("/uploaded") @ResponseBody public RestResult uploaded(HttpServletRequest request) { boolean isMultipart = ServletFileUpload.isMultipartContent(request); System.out.println("是否有上传文件:"+isMultipart); if (isMultipart == false) { return RestResult.error(1,"表单中不含文件"); } List<MultipartFile> list = ((MultipartHttpServletRequest)request).getFiles("files"); if (list.isEmpty()) { return RestResult.error(1,"文件不存在"); } for (MultipartFile multipartFile : list) { if (list.isEmpty()) { continue; } // 文件名 String fileName = multipartFile.getOriginalFilename(); System.out.println("文件名: " + fileName); // file size: Long length = multipartFile.getSize(); System.out.println("files size :"+length); // 文件后缀 int lastDot = fileName.lastIndexOf("."); lastDot++; String fileType = fileName.substring(lastDot); // 重新生成唯一文件名,用于存储数据库 String fileSn = UUID.randomUUID().toString(); Map<String, String> map2 = new HashMap<String, String>(); String destFilePath = FILE_BASE_PATH+"/"+fileSn+"."+fileType; File dest = new File(destFilePath); try { multipartFile.transferTo(dest); } catch (IOException e) { System.out.println("save ioexception"); e.printStackTrace(); return RestResult.error(1,"上传失败"); } } return RestResult.success(0,"上传成功"); } }
2,result/RestResult.java
//api通用返回数据 public class RestResult<T> { //uuid,用作唯一标识符,供序列化和反序列化时检测是否一致 private static final long serialVersionUID = 7498483649536881777L; //标识代码,0表示成功,非0表示出错 private Integer code; //提示信息,通常供报错时使用 private String msg; //正常返回时返回的数据 private T data; //constructor public RestResult() { } //constructor public RestResult(Integer status, String msg, T data) { this.code = status; this.msg = msg; this.data = data; } //返回成功数据 public RestResult success(T data) { return new RestResult(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMsg(), data); } public static RestResult success(Integer code,String msg) { return new RestResult(code, msg, null); } //返回出错数据 public static RestResult error(ResponseCode code) { return new RestResult(code.getCode(), code.getMsg(), null); } public static RestResult error(Integer code,String msg) { return new RestResult(code, msg, null); } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
3,templates/image/upload.html
<html lang="en"> <head> <script type="text/javascript" language="JavaScript" src="/js/jquery-1.6.2.min.js"></script> </head> <body> <div style="width:100%;height:20px;background:#ffffff;font-size: 16px;" ></div> <div id="content" style="width:800px;"> <div style="width:800px;float:left;"> <!--====================main begin=====================--> <div style="width:260px;height:200px;float:left;background: #eeeeee;padding-left: 10px;padding-top: 10px;"> 单文件上传<br/> 说明:不能多选<br/> <input id="fileone" type="file" name="fileone" /><br/><br/> <input type="button" name="go" value="单文件上传" onclick="go_single_add()" /> </div> <!--====================main end=====================--> </div> </div> <script> //单文件上传 function go_single_add(){ //把表单中选中的文件添加到postdata var postdata=new FormData(); for (var i=0;i<$("#fileone")[0].files.length;i++){ postdata.append("files",$("#fileone")[0].files[i]) } $.ajax({ type:"POST", url:"/file/uploaded", data:postdata, //返回数据的格式 datatype: "json",//"xml", "html", "script", "json", "jsonp", "text". processData: false, contentType: false, //成功返回之后调用的函数 success:function(data){ if (data.code == 0) { alert('上传成功:'+data.msg); //window.location.href="/image/imagelist"; } else { alert("上传失败:"+data.msg); } }, //调用执行后调用的函数 complete: function(XMLHttpRequest, textStatus){ }, //调用出错执行的函数 error: function(XMLHttpRequest, textStatus, errorThrown){ alert(XMLHttpRequest.readyState + XMLHttpRequest.status + XMLHttpRequest.responseText); } }); } </script> </body> </html>
4,controller/FileControllerTest.java
import com.jayway.jsonpath.JsonPath; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import java.io.File; import java.io.FileInputStream; import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; //import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; @AutoConfigureMockMvc @SpringBootTest class FileControllerTest { @Autowired private MockMvc mockMvc; @Test @DisplayName("上传文件成功") void uploaded() throws Exception { //文件之外的参数 String key1 = "这是第一个文件的说明"; String key2 = "这是第二个文件的说明"; File file2 = new File("/data/image/2.jpg"); MockMultipartFile mFile2 = new MockMultipartFile("files", "2.jpg", MediaType.TEXT_PLAIN_VALUE, new FileInputStream(file2)); File file3 = new File("/data/image/3.jpg"); MockMultipartFile mFile3 = new MockMultipartFile("files", "3.jpg", MediaType.TEXT_PLAIN_VALUE, new FileInputStream(file3)); MvcResult mvcResult = mockMvc.perform(multipart("/file/uploaded") .file(mFile2) .file(mFile3) .param("key1", key1) .param("key2", key2)) .andExpect(status().isOk()) .andReturn(); String content = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); System.out.println(content); int code = JsonPath.parse(content).read("$.code"); assertThat(code, equalTo(0)); } @Test @DisplayName("上传文件失败") void uploadedFail() throws Exception { //文件之外的参数 String key1 = "这是第一个文件的说明"; String key2 = "这是第二个文件的说明"; MvcResult mvcResult = mockMvc.perform(post("/file/uploaded") .param("key1", key1) .param("key2", key2)) .andExpect(status().isOk()) .andReturn(); String content = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); System.out.println(content); int code = JsonPath.parse(content).read("$.code"); assertThat(code, equalTo(1)); } }
四,测试效果
1,通过web页面访问
http://127.0.0.1:8080/file/upload
上传成功:
上传失败:
2,运行测试:
查看控制台:
上传成功:
是否有上传文件:true 文件名: 2.jpg files size :52066 文件名: 3.jpg files size :9576 {"code":0,"msg":"上传成功","data":null}
上传失败:
是否有上传文件:false {"code":1,"msg":"表单中不含文件","data":null}
五,查看spring boot的版本:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.4.3)