下载工作台
Spring Boot Web 开发

测试、安全与生产部署

试读上半部分 · 解锁后可读全文

第 11 章 · 测试、安全与生产部署

本章目标:使用 @SpringBootTestMockMvc 编写 Controller 层集成测试;配置 生产环境 安全项(HTTPS 反向代理、敏感配置外置);掌握 Spring Boot 可执行 jar 打包与 systemd 守护;完成 shop-spring-demo 上线前检查清单。

学时建议:4~5 小时(含 1.5 小时部署跟练)

前置ch07~ch10;了解 Linux 基础命令与 SSH。


11.1 测试分层策略

┌─────────────────────────────────────────────┐
│  @SpringBootTest + MockMvc   ← 本章重点      │
│  启动完整上下文,模拟 HTTP,不启真实浏览器     │
├─────────────────────────────────────────────┤
│  @DataJpaTest                ← Repository 层 │
├─────────────────────────────────────────────┤
│  纯单元测试 @ExtendWith(MockitoExtension)     │
└─────────────────────────────────────────────┘
类型速度覆盖
单元测试单类逻辑
MockMvcWeb 层 + Security 过滤链
全量 E2E真实浏览器/TestRestTemplate
教学项目 shop-spring-demo;测试库可用 H2 或 Testcontainers MySQL(选修)。

11.2 测试依赖与配置

pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>

src/test/resources/application-test.yml

spring:
  datasource:
    url: jdbc:h2:mem:shop_test;MODE=MySQL
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: create-drop
  data:
    redis:
      host: 127.0.0.1
      port: 6379

upload:
  base-dir: ./uploads-test

11.3 @SpringBootTest 与 MockMvc

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class ProductApiTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ProductRepository productRepository;

    @BeforeEach
    void setUp() {
        productRepository.deleteAll();
        Product p = new Product();
        p.setName("测试商品");
        p.setPrice(new BigDecimal("99.00"));
        p.setPublished(true);
        productRepository.save(p);
    }

    @Test
    void listProducts_returnsOk() throws Exception {
        mockMvc.perform(get("/api/products")
                        .param("page", "0")
                        .param("size", "10"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data.items[0].name").value("测试商品"));
    }
}
注解作用
@SpringBootTest加载完整 ApplicationContext
@AutoConfigureMockMvc注入 MockMvc
@ActiveProfiles("test")使用 test 配置
@Transactional(选修)测试后回滚 DB

11.4 MockMvc 常用断言

mockMvc.perform(post("/api/products")
        .contentType(MediaType.APPLICATION_JSON)
        .content("""
            {"name":"新商品","price":19.9,"stock":100}
            """))
    .andExpect(status().isOk())
    .andExpect(jsonPath("$.code").value(0))
    .andExpect(jsonPath("$.data.name").value("新商品"));

校验失败 400

mockMvc.perform(post("/api/products")
        .contentType(MediaType.APPLICATION_JSON)
        .content("{\"name\":\"\",\"price\":-1}"))
    .andExpect(status().isBadRequest())
    .andExpect(jsonPath("$.code").value(40001));
方法用途
get/post/put/deleteHTTP 方法
contentType / contentJSON 体
header / cookie认证头
andExpect(status())HTTP 状态
andExpect(jsonPath())JSON 字段
andDo(print())调试打印响应

11.5 Spring Security 测试

@Test
@WithMockUser(username = "admin", roles = "ADMIN")
void createProduct_withAuth() throws Exception {
    mockMvc.perform(post("/api/products")
            .contentType(MediaType.APPLICATION_JSON)
            .content("{\"name\":\"权限商品\",\"price\":1,\"stock\":1}"))
        .andExpect(status().isOk());
}

@Test
void createProduct_withoutAuth_forbidden() throws Exception {
    mockMvc.perform(post("/api/products")
            .contentType(MediaType.APPLICATION_JSON)
            .content("{}"))
        .andExpect(status().isUnauthorized());
}

JWT 场景可用 SecurityMockMvcRequestPostProcessors.jwt()

mockMvc.perform(get("/api/orders/me")
        .with(jwt().jwt(j -> j.subject("user1"))))
    .andExpect(status().isOk());

11.6 生产配置要点

配置项devprod
ddl-autoupdatevalidate / none
show-sqltruefalse
日志级别DEBUG 包INFO/WARN
密钥本地占位环境变量

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。