Browse Source

调试单元测试功能

dev-V1.0.1
庄锐波 7 months ago
parent
commit
1c7980b00f
  1. 2
      ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/DictController.java
  2. 190
      ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/QrCodeController.java
  3. 193
      ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/ZdxtFileUtilController.java
  4. 3
      script/sql/zfjd-refactoring-v1/009-修改执法码相关的表.sql
  5. 404
      zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/QrCodeControllerTest.java
  6. 482
      zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/ZdxtFileUtilControllerTest.java

2
ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/DictController.java

@ -16,7 +16,7 @@ import java.util.List;
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("/app")
@RequestMapping("/common/dict")
public class DictController {
private final ISysDictDataService dictDataService;

190
ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/QrCodeController.java

@ -0,0 +1,190 @@
package com.zdxt.enforcementcode.controller;
import com.zdxt.enforcementcode.domain.vo.QrCodeGenerateHistoryVo;
import com.zdxt.enforcementcode.util.QrCodeUtil;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* 二维码生成通用接口
* <p>
* 提供二维码生成(标准黑白 / 蓝色带 LOGO)、Base64 编码、二维码解析等通用能力。
* 生成后自动上传到 OSS 并保存 zdxt_file 和 qr_code_generate_history 记录。
* </p>
*
* @author zdxt
*/
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/common/qrcode")
public class QrCodeController extends BaseController {
/**
* 生成标准黑白二维码(默认尺寸 300px),上传 OSS 并保存记录
*
* @param content 二维码内容(通常为 URL)
* @param enterpriseNumber 企业纳税识别号
* @param businessId 关联的业务ID
* @return 二维码生成历史记录
*/
@Log(title = "二维码生成", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/generate")
public R<QrCodeGenerateHistoryVo> generate(
@NotBlank(message = "二维码内容不能为空") @RequestParam String content,
@NotBlank(message = "企业纳税识别号不能为空") @RequestParam String enterpriseNumber,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId) {
QrCodeGenerateHistoryVo vo = QrCodeUtil.generateAndSave(content, enterpriseNumber, businessId);
return R.ok(vo);
}
/**
* 生成标准黑白二维码(可指定分类代码和尺寸),上传 OSS 并保存记录
*
* @param content 二维码内容
* @param enterpriseNumber 企业纳税识别号
* @param businessId 关联的业务ID
* @param sortCode 分类代码(可为空)
* @param size 二维码尺寸(像素)
* @return 二维码生成历史记录
*/
@Log(title = "二维码生成", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/generateWithSize")
public R<QrCodeGenerateHistoryVo> generateWithSize(
@NotBlank(message = "二维码内容不能为空") @RequestParam String content,
@NotBlank(message = "企业纳税识别号不能为空") @RequestParam String enterpriseNumber,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId,
@RequestParam(required = false) String sortCode,
@NotNull(message = "二维码尺寸不能为空") @RequestParam Integer size) {
QrCodeGenerateHistoryVo vo = QrCodeUtil.generateAndSave(content, enterpriseNumber, businessId, sortCode, size);
return R.ok(vo);
}
/**
* 生成蓝色二维码(含默认 LOGO),上传 OSS 并保存记录
*
* @param content 二维码内容
* @param enterpriseNumber 企业纳税识别号
* @param businessId 关联的业务ID
* @param size 二维码尺寸(像素)
* @return 二维码生成历史记录
*/
@Log(title = "蓝色二维码生成", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/generateBlueWithLogo")
public R<QrCodeGenerateHistoryVo> generateBlueWithLogo(
@NotBlank(message = "二维码内容不能为空") @RequestParam String content,
@NotBlank(message = "企业纳税识别号不能为空") @RequestParam String enterpriseNumber,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId,
@NotNull(message = "二维码尺寸不能为空") @RequestParam Integer size) {
QrCodeGenerateHistoryVo vo = QrCodeUtil.generateBlueWithLogoAndSave(content, enterpriseNumber, businessId, size);
return R.ok(vo);
}
/**
* 生成蓝色二维码(含默认 LOGO、可指定分类代码),上传 OSS 并保存记录
*
* @param content 二维码内容
* @param enterpriseNumber 企业纳税识别号
* @param businessId 关联的业务ID
* @param sortCode 分类代码(可为空)
* @param size 二维码尺寸(像素)
* @return 二维码生成历史记录
*/
@Log(title = "蓝色二维码生成", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/generateBlueWithLogoAndSort")
public R<QrCodeGenerateHistoryVo> generateBlueWithLogoAndSort(
@NotBlank(message = "二维码内容不能为空") @RequestParam String content,
@NotBlank(message = "企业纳税识别号不能为空") @RequestParam String enterpriseNumber,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId,
@RequestParam(required = false) String sortCode,
@NotNull(message = "二维码尺寸不能为空") @RequestParam Integer size) {
QrCodeGenerateHistoryVo vo = QrCodeUtil.generateBlueWithLogoAndSave(content, enterpriseNumber, businessId, sortCode, size);
return R.ok(vo);
}
/**
* 生成标准黑白二维码的 Base64 编码字符串(含 data:image 前缀)
*
* @param content 二维码内容
* @param size 二维码尺寸(像素)
* @return Base64 编码字符串
*/
@GetMapping("/base64")
public R<String> toBase64(
@NotBlank(message = "二维码内容不能为空") @RequestParam String content,
@NotNull(message = "二维码尺寸不能为空") @RequestParam Integer size) {
String base64 = QrCodeUtil.toBase64(content, size);
return R.ok(base64);
}
/**
* 生成蓝色二维码(含 LOGO)的 Base64 编码字符串
*
* @param content 二维码内容
* @param size 二维码尺寸(像素)
* @return Base64 编码字符串
*/
@GetMapping("/blueBase64WithLogo")
public R<String> toBlueBase64WithLogo(
@NotBlank(message = "二维码内容不能为空") @RequestParam String content,
@NotNull(message = "二维码尺寸不能为空") @RequestParam Integer size) {
String base64 = QrCodeUtil.toBlueBase64WithLogo(content, size);
return R.ok(base64);
}
/**
* 解析上传的二维码图片,返回二维码内容
*
* @param file 二维码图片文件
* @return 解析出的文本内容
*/
@PostMapping("/decode")
public R<String> decode(@RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return R.fail("上传的二维码图片不能为空");
}
Path tempFile = null;
try {
// 将上传文件写入临时文件以供解析
String originalFilename = file.getOriginalFilename();
String suffix = (originalFilename != null && originalFilename.contains("."))
? originalFilename.substring(originalFilename.lastIndexOf("."))
: ".jpg";
tempFile = Files.createTempFile("qr_decode_", suffix);
file.transferTo(tempFile.toFile());
String result = QrCodeUtil.decodeQrCode(tempFile.toFile());
return R.ok("解析成功", result);
} catch (IOException e) {
log.error("解析二维码失败: {}", e.getMessage(), e);
return R.fail("解析二维码失败: " + e.getMessage());
} finally {
// 清理临时文件
if (tempFile != null) {
try {
Files.deleteIfExists(tempFile);
} catch (IOException ignored) {
}
}
}
}
}

193
ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/ZdxtFileUtilController.java

@ -0,0 +1,193 @@
package com.zdxt.enforcementcode.controller;
import com.zdxt.enforcementcode.domain.vo.ZdxtFileVo;
import com.zdxt.enforcementcode.util.ZdxtFileUtil;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 附件管理通用接口
* <p>
* 封装文件上传(本地存储)、查询、删除等通用能力,
* 基于 {@link ZdxtFileUtil} 工具类,文件保存到本地磁盘并记录到 zdxt_file 表。
* </p>
*
* @author zdxt
*/
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/common/file")
public class ZdxtFileUtilController extends BaseController {
// ==================== 上传接口 ====================
/**
* 上传单个文件(自动获取当前登录用户信息)
*
* @param file 上传的文件
* @param businessId 业务ID(关联的业务主键)
* @return 附件视图对象
*/
@Log(title = "附件上传", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/upload")
public R<ZdxtFileVo> upload(
@RequestParam("file") MultipartFile file,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId) {
ZdxtFileVo vo = ZdxtFileUtil.uploadFile(file, businessId);
return R.ok(vo);
}
/**
* 上传单个文件,带分类代码(自动获取当前登录用户信息)
*
* @param file 上传的文件
* @param businessId 业务ID
* @param sortCode 分类代码
* @return 附件视图对象
*/
@Log(title = "附件上传", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/uploadWithSort")
public R<ZdxtFileVo> uploadWithSort(
@RequestParam("file") MultipartFile file,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId,
@RequestParam(required = false) String sortCode) {
ZdxtFileVo vo = ZdxtFileUtil.uploadFile(file, businessId, sortCode);
return R.ok(vo);
}
/**
* 批量上传文件
*
* @param files 文件数组
* @param businessId 业务ID
* @return 附件视图对象列表
*/
@Log(title = "附件批量上传", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/uploadBatch")
public R<List<ZdxtFileVo>> uploadBatch(
@RequestParam("files") MultipartFile[] files,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId) {
List<ZdxtFileVo> list = ZdxtFileUtil.uploadFiles(files, businessId);
return R.ok(list);
}
/**
* 批量上传文件,带分类代码
*
* @param files 文件数组
* @param businessId 业务ID
* @param sortCode 分类代码
* @return 附件视图对象列表
*/
@Log(title = "附件批量上传", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/uploadBatchWithSort")
public R<List<ZdxtFileVo>> uploadBatchWithSort(
@RequestParam("files") MultipartFile[] files,
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId,
@RequestParam(required = false) String sortCode) {
List<ZdxtFileVo> list = ZdxtFileUtil.uploadFiles(files, businessId, sortCode);
return R.ok(list);
}
// ==================== 查询接口 ====================
/**
* 根据附件ID查询附件信息
*
* @param guid 附件主键ID
* @return 附件视图对象
*/
@GetMapping("/{guid}")
public R<ZdxtFileVo> getByGuid(
@NotBlank(message = "附件ID不能为空") @PathVariable String guid) {
ZdxtFileVo vo = ZdxtFileUtil.queryByGuid(guid);
return R.ok(vo);
}
/**
* 根据业务ID查询附件列表
*
* @param businessId 业务ID
* @return 附件列表
*/
@GetMapping("/listByBusinessId")
public R<List<ZdxtFileVo>> listByBusinessId(
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId) {
List<ZdxtFileVo> list = ZdxtFileUtil.queryByBusinessId(businessId);
return R.ok(list);
}
/**
* 根据业务ID和分类代码查询附件列表
*
* @param businessId 业务ID
* @param sortCode 分类代码
* @return 附件列表
*/
@GetMapping("/listByBusinessIdAndSort")
public R<List<ZdxtFileVo>> listByBusinessIdAndSort(
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId,
@NotBlank(message = "分类代码不能为空") @RequestParam String sortCode) {
List<ZdxtFileVo> list = ZdxtFileUtil.queryByBusinessIdAndSortCode(businessId, sortCode);
return R.ok(list);
}
// ==================== 删除接口 ====================
/**
* 根据附件ID删除单个附件(同时删除本地文件)
*
* @param guid 附件主键ID
* @return 是否删除成功
*/
@Log(title = "附件删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{guid}")
public R<Void> deleteByGuid(
@NotBlank(message = "附件ID不能为空") @PathVariable String guid) {
return toAjax(ZdxtFileUtil.deleteByGuid(guid));
}
/**
* 根据附件ID批量删除附件(同时删除本地文件)
*
* @param guids 附件主键ID数组
* @return 是否删除成功
*/
@Log(title = "附件批量删除", businessType = BusinessType.DELETE)
@DeleteMapping("/batch/{guids}")
public R<Void> deleteByGuids(
@NotEmpty(message = "附件ID不能为空") @PathVariable String[] guids) {
return toAjax(ZdxtFileUtil.deleteByGuids(List.of(guids)));
}
/**
* 根据业务ID删除所有关联附件(同时删除本地文件)
*
* @param businessId 业务ID
* @return 是否删除成功
*/
@Log(title = "按业务ID删除附件", businessType = BusinessType.DELETE)
@DeleteMapping("/deleteByBusinessId")
public R<Void> deleteByBusinessId(
@NotBlank(message = "业务ID不能为空") @RequestParam String businessId) {
return toAjax(ZdxtFileUtil.deleteByBusinessId(businessId));
}
}

3
script/sql/zfjd-refactoring-v1/009-修改执法码相关的表.sql

@ -15,3 +15,6 @@ ALTER TABLE zdxt_file
ALTER TABLE zdxt_file
ADD COLUMN create_time datetime NULL COMMENT '创建时间' AFTER create_by
ALTER TABLE zdxt_file
ADD COLUMN tenant_id varchar(50) NULL COMMENT '创建者' AFTER create_by

404
zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/QrCodeControllerTest.java

@ -0,0 +1,404 @@
package com.zdxt.rest.test;
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpUtil;
import org.dromara.ZdxtAdminApplication;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import org.junit.jupiter.api.*;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
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 javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* QrCodeController 二维码通用接口测试
* <p>
* 分为三类:
* 1. 参数校验测试(不依赖 OSS/DB)
* 2. Base64 / 解析测试(纯计算,不依赖 OSS/DB)
* 3. 生成+保存集成测试(需要 Spring 上下文、OSS 和数据库)
* </p>
*
* @author zdxt
*/
@SpringBootTest(classes = ZdxtAdminApplication.class)
@AutoConfigureMockMvc
@DisplayName("QrCodeController 二维码通用接口测试")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class QrCodeControllerTest {
@Autowired
private MockMvc mockMvc;
private static final String BASE_URL = "/common/qrcode";
private static final String TEST_CONTENT = "https://www.example.com/qr?id=ctrl_test";
private static final String TEST_ENTERPRISE_NUMBER = "91110000CTRL001";
private static final String TEST_BUSINESS_ID = "TEST_CTRL_QR_001";
private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e";
/** 登录后获取的 token */
private String token;
@BeforeEach
public void setUp() {
// 初始化 Sa-Token 上下文(非 Web 环境下 StpUtil.login 需要)
SaTokenContextMockUtil.setMockContext();
// 设置模拟请求上下文(UserActionListener 需要从 Request 中获取 User-Agent)
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest));
// 构造测试用登录用户
LoginUser loginUser = new LoginUser();
loginUser.setUserId(1L);
loginUser.setUserType("sys_user");
loginUser.setTenantId("000000");
loginUser.setUsername("test_admin");
loginUser.setNickname("测试管理员");
loginUser.setDeptId("103");
loginUser.setDeptName("测试部门");
loginUser.setRolePermission(new HashSet<>());
loginUser.setMenuPermission(new HashSet<>());
// 模拟登录并获取 token
SaLoginParameter param = new SaLoginParameter();
param.setExtra(LoginHelper.CLIENT_KEY, TEST_CLIENT_ID);
LoginHelper.login(loginUser, param);
token = StpUtil.getTokenValue();
}
@AfterEach
public void tearDown() {
try {
StpUtil.logout();
} catch (Exception ignored) {
}
RequestContextHolder.resetRequestAttributes();
SaTokenContextMockUtil.clearContext();
}
// ==================== 参数校验测试 ====================
@DisplayName("生成二维码 - 缺少 content 参数应返回失败")
@Test
@Order(1)
public void testGenerateMissingContent() throws Exception {
mockMvc.perform(post(BASE_URL + "/generate")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.param("businessId", TEST_BUSINESS_ID)
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("生成二维码 - 缺少 enterpriseNumber 参数应返回失败")
@Test
@Order(1)
public void testGenerateMissingEnterpriseNumber() throws Exception {
mockMvc.perform(post(BASE_URL + "/generate")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("businessId", TEST_BUSINESS_ID)
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("生成二维码 - 缺少 businessId 参数应返回失败")
@Test
@Order(1)
public void testGenerateMissingBusinessId() throws Exception {
mockMvc.perform(post(BASE_URL + "/generate")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("自定义尺寸生成 - 缺少 size 参数应返回失败")
@Test
@Order(1)
public void testGenerateWithSizeMissingSize() throws Exception {
mockMvc.perform(post(BASE_URL + "/generateWithSize")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.param("businessId", TEST_BUSINESS_ID)
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("蓝色二维码生成 - 缺少 size 参数应返回失败")
@Test
@Order(1)
public void testGenerateBlueWithLogoMissingSize() throws Exception {
mockMvc.perform(post(BASE_URL + "/generateBlueWithLogo")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.param("businessId", TEST_BUSINESS_ID)
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isBadRequest());
}
// ==================== Base64 接口测试 ====================
@DisplayName("Base64 接口 - 缺少 content 参数应返回失败")
@Test
@Order(2)
public void testBase64MissingContent() throws Exception {
mockMvc.perform(get(BASE_URL + "/base64")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("size", "300"))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("Base64 接口 - 缺少 size 参数应返回失败")
@Test
@Order(2)
public void testBase64MissingSize() throws Exception {
mockMvc.perform(get(BASE_URL + "/base64")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("Base64 接口 - 正常生成标准二维码 Base64")
@Test
@Order(2)
public void testBase64Success() throws Exception {
MvcResult result = mockMvc.perform(get(BASE_URL + "/base64")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("size", "300"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty())
.andReturn();
String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
Assertions.assertTrue(responseBody.contains("data:image/jpeg;base64,"),
"返回数据应包含 Base64 前缀");
System.out.println("Base64 接口测试成功,响应长度: " + responseBody.length());
}
@DisplayName("蓝色 Base64 接口 - 正常生成蓝色二维码 Base64")
@Test
@Order(2)
public void testBlueBase64WithLogoSuccess() throws Exception {
MvcResult result = mockMvc.perform(get(BASE_URL + "/blueBase64WithLogo")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("size", "300"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty())
.andReturn();
String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
Assertions.assertTrue(responseBody.contains("data:image/jpeg;base64,"),
"返回数据应包含 Base64 前缀");
System.out.println("蓝色 Base64 接口测试成功");
}
// ==================== 二维码解析接口测试 ====================
@DisplayName("解析接口 - 上传空文件应返回失败")
@Test
@Order(3)
public void testDecodeEmptyFile() throws Exception {
MockMultipartFile emptyFile = new MockMultipartFile(
"file", "empty.jpg", "image/jpeg", new byte[0]
);
mockMvc.perform(multipart(BASE_URL + "/decode").file(emptyFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(500));
}
@DisplayName("解析接口 - 正常解析二维码图片")
@Test
@Order(3)
public void testDecodeSuccess() throws Exception {
// 通过 ZXing 生成一张真实的二维码图片作为测试输入
com.google.zxing.common.BitMatrix bitMatrix = new com.google.zxing.MultiFormatWriter()
.encode(TEST_CONTENT, com.google.zxing.BarcodeFormat.QR_CODE, 300, 300);
BufferedImage image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < 300; x++) {
for (int y = 0; y < 300; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", baos);
byte[] imageBytes = baos.toByteArray();
MockMultipartFile qrFile = new MockMultipartFile(
"file", "qrcode.jpg", "image/jpeg", imageBytes
);
mockMvc.perform(multipart(BASE_URL + "/decode").file(qrFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").value(TEST_CONTENT));
System.out.println("二维码解析接口测试成功");
}
@DisplayName("解析接口 - 上传非二维码图片应返回失败")
@Test
@Order(3)
public void testDecodeNonQrImage() throws Exception {
// 生成一张纯白色图片(非二维码)
BufferedImage whiteImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < 100; x++) {
for (int y = 0; y < 100; y++) {
whiteImage.setRGB(x, y, 0xFFFFFFFF);
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(whiteImage, "jpg", baos);
MockMultipartFile notQrFile = new MockMultipartFile(
"file", "not_qr.jpg", "image/jpeg", baos.toByteArray()
);
mockMvc.perform(multipart(BASE_URL + "/decode").file(notQrFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(500));
System.out.println("非二维码图片解析正确返回失败");
}
// ==================== 生成+保存集成测试(需 OSS + DB) ====================
@DisplayName("生成标准二维码并保存 - 参数完整")
@Test
@Order(5)
public void testGenerateAndSave() throws Exception {
mockMvc.perform(post(BASE_URL + "/generate")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.param("businessId", TEST_BUSINESS_ID)
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty())
.andExpect(jsonPath("$.data.id").isNotEmpty())
.andExpect(jsonPath("$.data.qrCodeUrl").isNotEmpty())
.andExpect(jsonPath("$.data.enterpriseNumber").value(TEST_ENTERPRISE_NUMBER));
System.out.println("标准二维码生成并保存接口测试成功");
}
@DisplayName("生成自定义尺寸二维码并保存 - 带分类代码")
@Test
@Order(5)
public void testGenerateWithSizeAndSave() throws Exception {
mockMvc.perform(post(BASE_URL + "/generateWithSize")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.param("businessId", TEST_BUSINESS_ID)
.param("sortCode", "QR_SORT_CTRL")
.param("size", "400")
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty());
System.out.println("自定义尺寸二维码生成接口测试成功");
}
@DisplayName("生成蓝色二维码并保存")
@Test
@Order(5)
public void testGenerateBlueWithLogoAndSave() throws Exception {
mockMvc.perform(post(BASE_URL + "/generateBlueWithLogo")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.param("businessId", TEST_BUSINESS_ID)
.param("size", "300")
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.qrCodeUrl").isNotEmpty());
System.out.println("蓝色二维码生成并保存接口测试成功");
}
@DisplayName("生成蓝色二维码(含分类代码)并保存")
@Test
@Order(5)
public void testGenerateBlueWithLogoAndSortAndSave() throws Exception {
mockMvc.perform(post(BASE_URL + "/generateBlueWithLogoAndSort")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("content", TEST_CONTENT)
.param("enterpriseNumber", TEST_ENTERPRISE_NUMBER)
.param("businessId", TEST_BUSINESS_ID)
.param("sortCode", "QR_BLUE_CTRL")
.param("size", "500")
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty());
System.out.println("蓝色二维码(含分类)生成接口测试成功");
}
}

482
zdxt-web-server/zdxt-admin-web-server/src/test/java/com/zdxt/rest/test/ZdxtFileUtilControllerTest.java

@ -0,0 +1,482 @@
package com.zdxt.rest.test;
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.stp.StpUtil;
import com.zdxt.enforcementcode.domain.vo.ZdxtFileVo;
import com.zdxt.enforcementcode.util.ZdxtFileUtil;
import org.dromara.ZdxtAdminApplication;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import org.junit.jupiter.api.*;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
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.nio.charset.StandardCharsets;
import java.util.HashSet;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* ZdxtFileUtilController 附件管理通用接口测试
* <p>
* 分为四类:
* 1. 上传接口测试(单文件 / 批量 / 带分类代码)
* 2. 查询接口测试(按 guid / 按 businessId / 按 businessId + sortCode)
* 3. 删除接口测试(单个 / 批量 / 按 businessId)
* 4. 参数校验测试
* </p>
*
* @author zdxt
*/
@SpringBootTest(classes = ZdxtAdminApplication.class)
@AutoConfigureMockMvc
@DisplayName("ZdxtFileUtilController 附件管理通用接口测试")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ZdxtFileUtilControllerTest {
@Autowired
private MockMvc mockMvc;
private static final String BASE_URL = "/common/file";
private static final String TEST_BUSINESS_ID = "TEST_CTRL_FILE_001";
private static final String TEST_SORT_CODE = "CTRL_SORT";
private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e";
/** 登录后获取的 token */
private String token;
/** 记录上传后的 guid,供后续查询/删除使用 */
private static String uploadedGuid;
@BeforeEach
public void setUp() {
// 初始化 Sa-Token 上下文(非 Web 环境下 StpUtil.login 需要)
SaTokenContextMockUtil.setMockContext();
// 设置模拟请求上下文(UserActionListener 需要从 Request 中获取 User-Agent)
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest));
// 构造测试用登录用户
LoginUser loginUser = new LoginUser();
loginUser.setUserId(1L);
loginUser.setUserType("sys_user");
loginUser.setTenantId("000000");
loginUser.setUsername("test_admin");
loginUser.setNickname("测试管理员");
loginUser.setDeptId("103");
loginUser.setDeptName("测试部门");
loginUser.setRolePermission(new HashSet<>());
loginUser.setMenuPermission(new HashSet<>());
// 模拟登录并获取 token
SaLoginParameter param = new SaLoginParameter();
param.setExtra(LoginHelper.CLIENT_KEY, TEST_CLIENT_ID);
LoginHelper.login(loginUser, param);
token = StpUtil.getTokenValue();
}
@AfterEach
public void tearDown() {
try {
StpUtil.logout();
} catch (Exception ignored) {
}
RequestContextHolder.resetRequestAttributes();
SaTokenContextMockUtil.clearContext();
}
// ==================== 上传接口测试 ====================
@DisplayName("上传单个文件 - 正常上传")
@Test
@Order(1)
public void testUploadFile() throws Exception {
MockMultipartFile mockFile = new MockMultipartFile(
"file", "controller-test.txt", "text/plain",
"Controller upload test content.".getBytes(StandardCharsets.UTF_8)
);
MvcResult result = mockMvc.perform(multipart(BASE_URL + "/upload")
.file(mockFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isNotEmpty())
.andExpect(jsonPath("$.data.guid").isNotEmpty())
.andExpect(jsonPath("$.data.businessId").value(TEST_BUSINESS_ID))
.andExpect(jsonPath("$.data.fileName").value("controller-test.txt"))
.andExpect(jsonPath("$.data.fileSuffix").value(".txt"))
.andExpect(jsonPath("$.data.fileType").value("txt"))
.andExpect(jsonPath("$.data.uploadPath").isNotEmpty())
.andReturn();
// 从响应中提取 guid 供后续测试使用
String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
// 简单解析 guid(集成测试中直接使用工具查询更可靠)
if (responseBody.contains("\"guid\"")) {
int start = responseBody.indexOf("\"guid\":\"") + 8;
int end = responseBody.indexOf("\"", start);
uploadedGuid = responseBody.substring(start, end);
}
System.out.println("单文件上传成功: guid=" + uploadedGuid);
}
@DisplayName("上传单个文件(带分类代码)- 正常上传")
@Test
@Order(1)
public void testUploadFileWithSort() throws Exception {
MockMultipartFile mockFile = new MockMultipartFile(
"file", "sorted-file.pdf", "application/pdf",
"PDF content simulation".getBytes(StandardCharsets.UTF_8)
);
mockMvc.perform(multipart(BASE_URL + "/uploadWithSort")
.file(mockFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID)
.param("sortCode", TEST_SORT_CODE))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.guid").isNotEmpty())
.andExpect(jsonPath("$.data.fileSuffix").value(".pdf"));
System.out.println("带分类代码的文件上传成功");
}
@DisplayName("批量上传文件 - 正常上传")
@Test
@Order(1)
public void testUploadBatch() throws Exception {
MockMultipartFile file1 = new MockMultipartFile(
"files", "batch1.txt", "text/plain", "batch content 1".getBytes()
);
MockMultipartFile file2 = new MockMultipartFile(
"files", "batch2.txt", "text/plain", "batch content 2".getBytes()
);
mockMvc.perform(multipart(BASE_URL + "/uploadBatch")
.file(file1)
.file(file2)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(2));
System.out.println("批量上传成功");
}
@DisplayName("批量上传文件(带分类代码)- 正常上传")
@Test
@Order(1)
public void testUploadBatchWithSort() throws Exception {
MockMultipartFile file1 = new MockMultipartFile(
"files", "batch_sort1.txt", "text/plain", "sort batch 1".getBytes()
);
MockMultipartFile file2 = new MockMultipartFile(
"files", "batch_sort2.txt", "text/plain", "sort batch 2".getBytes()
);
mockMvc.perform(multipart(BASE_URL + "/uploadBatchWithSort")
.file(file1)
.file(file2)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID)
.param("sortCode", TEST_SORT_CODE))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray());
System.out.println("带分类代码的批量上传成功");
}
// ==================== 参数校验测试 ====================
@DisplayName("上传文件 - 缺少 businessId 应返回失败")
@Test
@Order(1)
public void testUploadMissingBusinessId() throws Exception {
MockMultipartFile mockFile = new MockMultipartFile(
"file", "test.txt", "text/plain", "test".getBytes()
);
mockMvc.perform(multipart(BASE_URL + "/upload")
.file(mockFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("上传文件 - 空文件应返回失败")
@Test
@Order(1)
public void testUploadEmptyFile() throws Exception {
MockMultipartFile emptyFile = new MockMultipartFile(
"file", "empty.txt", "text/plain", new byte[0]
);
mockMvc.perform(multipart(BASE_URL + "/upload")
.file(emptyFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(500));
System.out.println("空文件上传正确返回失败");
}
@DisplayName("上传文件 - 无后缀文件名应返回失败")
@Test
@Order(1)
public void testUploadFileWithoutSuffix() throws Exception {
MockMultipartFile noSuffixFile = new MockMultipartFile(
"file", "noextension", "application/octet-stream", "data".getBytes()
);
mockMvc.perform(multipart(BASE_URL + "/upload")
.file(noSuffixFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(500));
System.out.println("无后缀文件上传正确返回失败");
}
// ==================== 查询接口测试 ====================
@DisplayName("根据 guid 查询附件信息")
@Test
@Order(2)
public void testGetByGuid() throws Exception {
if (uploadedGuid == null) {
System.out.println("跳过: 依赖上传测试先执行");
return;
}
mockMvc.perform(get(BASE_URL + "/{guid}", uploadedGuid)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.guid").value(uploadedGuid));
System.out.println("按 guid 查询成功: " + uploadedGuid);
}
@DisplayName("根据 businessId 查询附件列表")
@Test
@Order(2)
public void testListByBusinessId() throws Exception {
mockMvc.perform(get(BASE_URL + "/listByBusinessId")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray());
System.out.println("按 businessId 查询成功");
}
@DisplayName("根据 businessId 和 sortCode 查询附件列表")
@Test
@Order(2)
public void testListByBusinessIdAndSort() throws Exception {
mockMvc.perform(get(BASE_URL + "/listByBusinessIdAndSort")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID)
.param("sortCode", TEST_SORT_CODE))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray());
System.out.println("按 businessId + sortCode 查询成功");
}
@DisplayName("查询附件列表 - 缺少 businessId 应返回失败")
@Test
@Order(2)
public void testListByBusinessIdMissingParam() throws Exception {
mockMvc.perform(get(BASE_URL + "/listByBusinessId")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isBadRequest());
}
@DisplayName("查询附件列表 - 缺少 sortCode 应返回失败")
@Test
@Order(2)
public void testListByBusinessIdAndSortMissingSortCode() throws Exception {
mockMvc.perform(get(BASE_URL + "/listByBusinessIdAndSort")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andDo(print())
.andExpect(status().isBadRequest());
}
// ==================== 删除接口测试 ====================
@DisplayName("根据 guid 删除附件")
@Test
@Order(3)
public void testDeleteByGuid() throws Exception {
// 先上传一个文件用于删除
MockMultipartFile mockFile = new MockMultipartFile(
"file", "to-delete.txt", "text/plain", "delete me".getBytes()
);
MvcResult uploadResult = mockMvc.perform(multipart(BASE_URL + "/upload")
.file(mockFile)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", "TEST_DEL_BIZ"))
.andExpect(status().isOk())
.andReturn();
String body = uploadResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
String guidToDelete = null;
if (body.contains("\"guid\"")) {
int start = body.indexOf("\"guid\":\"") + 8;
int end = body.indexOf("\"", start);
guidToDelete = body.substring(start, end);
}
Assertions.assertNotNull(guidToDelete, "上传后应有 guid");
// 执行删除
mockMvc.perform(delete(BASE_URL + "/{guid}", guidToDelete)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
System.out.println("按 guid 删除成功: " + guidToDelete);
}
@DisplayName("批量删除附件")
@Test
@Order(3)
public void testDeleteByGuids() throws Exception {
// 先上传两个文件
MockMultipartFile file1 = new MockMultipartFile(
"file", "del-batch1.txt", "text/plain", "batch del 1".getBytes()
);
MockMultipartFile file2 = new MockMultipartFile(
"file", "del-batch2.txt", "text/plain", "batch del 2".getBytes()
);
MvcResult r1 = mockMvc.perform(multipart(BASE_URL + "/upload")
.file(file1)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", "TEST_BATCH_DEL"))
.andExpect(status().isOk()).andReturn();
MvcResult r2 = mockMvc.perform(multipart(BASE_URL + "/upload")
.file(file2)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", "TEST_BATCH_DEL"))
.andExpect(status().isOk()).andReturn();
String body1 = r1.getResponse().getContentAsString(StandardCharsets.UTF_8);
String body2 = r2.getResponse().getContentAsString(StandardCharsets.UTF_8);
String guid1 = extractGuid(body1);
String guid2 = extractGuid(body2);
Assertions.assertNotNull(guid1);
Assertions.assertNotNull(guid2);
// 批量删除
mockMvc.perform(delete(BASE_URL + "/batch/{guids}", guid1 + "," + guid2)
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
System.out.println("批量删除成功: " + guid1 + ", " + guid2);
}
@DisplayName("按 businessId 删除所有关联附件")
@Test
@Order(4)
public void testDeleteByBusinessId() throws Exception {
mockMvc.perform(delete(BASE_URL + "/deleteByBusinessId")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
// 验证删除后查询为空
mockMvc.perform(get(BASE_URL + "/listByBusinessId")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID)
.param("businessId", TEST_BUSINESS_ID))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data.length()").value(0));
System.out.println("按 businessId 删除所有附件成功");
}
@DisplayName("按 businessId 删除 - 缺少参数应返回失败")
@Test
@Order(4)
public void testDeleteByBusinessIdMissingParam() throws Exception {
mockMvc.perform(delete(BASE_URL + "/deleteByBusinessId")
.header("Authorization", "Bearer " + token)
.header("clientid", TEST_CLIENT_ID))
.andDo(print())
.andExpect(status().isBadRequest());
}
// ==================== 工具方法 ====================
/**
* 从 JSON 响应中简单提取 guid 值
*/
private String extractGuid(String responseBody) {
if (responseBody != null && responseBody.contains("\"guid\"")) {
int start = responseBody.indexOf("\"guid\":\"") + 8;
int end = responseBody.indexOf("\"", start);
return responseBody.substring(start, end);
}
return null;
}
}
Loading…
Cancel
Save