欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

spring boot 单元测试:测试文件上传中的单元测试(spring boot 2.4.3)

最编程 2024-06-23 11:07:14
...

一,演示项目的相关信息

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)