Skip to content

集成测试与问题排查

一、集成测试:全链路验证

集成测试让"Controller → Service → Mapper → MySQL"真实跑通,用 MockMvc 模拟 HTTP 请求:

java
package com.mall.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mall.dto.CartAddDTO;
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.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc
class CartControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void 商品列表可查询() throws Exception {
        mockMvc.perform(get("/api/product/list")
                        .param("page", "1").param("size", "10"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data.records").exists());
    }

    @Test
    void 注册后可登录() throws Exception {
        mockMvc.perform(post("/api/auth/register")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("{\"username\":\"test01\",\"password\":\"123456\"}"))
                .andExpect(jsonPath("$.code").value(0));

        // SQL 层面唯一约束:重复注册应返回业务错误
        mockMvc.perform(post("/api/auth/register")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("{\"username\":\"test01\",\"password\":\"123456\"}"))
                .andExpect(jsonPath("$.code").value(500));
    }
}

注意事项:

  • 集成测试连真实数据库,跑之前保证 mall 库存在。
  • 可以把测试库与开发库隔离(application-test.yml 配独立库),避免污染数据。
  • 每个用例自己造数据并清理,顺序相互独立。

二、前端单元测试(可选加分)

Vue / React 项目都可用 Vitest + Testing Library(create-vue 脚手架默认带了 Vitest):

ts
// web-vue/src/views/HomeView.test.ts
import { describe, it, expect } from 'vitest'

describe('价格格式化', () => {
  it('数字转货币格式', () => {
    expect(formatPrice(2999)).toBe('¥2,999.00')
  })
})

前端测试重点放在纯函数/工具函数(格式化、计算),组件测试成本高,项目紧可后补。

三、问题排查工具箱

1. 看后端 SQL(MP 已默认打印)

==>  Preparing: SELECT id,name,price FROM product WHERE deleted=0 AND name LIKE ? ...
==> Parameters: %手机%(String)

这条 SQL 对不上预期 → 到这就能发现问题

2. 浏览器 Network 面板

  • 请求 URL 是否经过代理(Request URL 前应显示 localhost:5173,但请求到后端走通了)。
  • 响应:JSON 里 code/message/data 是否符合预期。

3. 后端日志分级排查

bash
# 控制台实时看
# 或查看日志文件(生产环境)
tail -f logs/application.log
grep -n "ERROR" logs/application.log

4. 常见疑难场景速查

场景排查方向
页面 502/504后端没启动 / 被代理但端口错了
数据偶发不一致事务边界放错、并发问题(看第 7 部分)
前端拿到的是旧数据浏览器缓存 / localStorage 里的旧 token
时区差 8 小时JDBC URL 加 serverTimezone=Asia/Shanghai
中文乱码建库用 utf8mb4、连接串加 characterEncoding=utf8

四、全链路冒烟测试(上线前必做)

用第 8 部分联调那套流程,写成一个脚本化冒烟清单,上线前快速过一遍:

bash
1. GET  /api/product/list code=0,有数据
2. POST /api/auth/register code=0
3. POST /api/auth/login 拿到 token
4. POST /api/cart(带token) code=0
5. POST /api/order(带token) code=0,库存减少
6. GET  /api/order/list 能看到刚下的单

可以手跑,也可以写进 CI(第 9 部分)每天自动跑一遍。

五、本章验收

  • [ ] CartControllerTest / ProductControllerTest 等集成测试通过
  • [ ] 会用 Network 面板 + MP 打印的 SQL 定位一个问题
  • [ ] 完成一次全链路冒烟
  • [ ] 顺手把常见的"时区/乱码"坑配置正确

核心心法

排错 = 缩小范围:前端 → 网络 → 后端 → SQL → 数据库,一层层往下找。用日志和数据定位,别凭感觉改代码。

基于 MIT 协议发布,可自由学习与修改