文档站点
Skip to content

数据库测试 ​

Laravel 用 RefreshDatabase + sqlite :memory: 跑数据库测试;Spring Boot 用 @DataJpaTest(JPA 层)或 Testcontainers(真实数据库)。核心原则一样:测试绝不碰开发/生产库。

方案一:@DataJpaTest(JPA 层测试,内存 H2) ​

只加载 JPA 相关 Bean,测试 Repository,秒级完成:

java
package com.example.blog.post;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;

@DataJpaTest
class PostRepositoryTest {

    @Autowired
    private PostRepository postRepository;

    @Test
    void 按状态查询() {
        // 保存测试数据
        Post p1 = new Post();
        p1.setTitle("发布帖");
        p1.setStatus(1);
        postRepository.save(p1);

        List<Post> published = postRepository.findByStatus(1);
        assertEquals(1, published.size());
    }

    @Test
    void 找不到返回空Optional() {
        Optional<Post> post = postRepository.findById(999L);
        assertTrue(post.isEmpty());
    }
}

TIP

@DataJpaTest 自动用 H2 + create-drop 建表,每个测试结束自动回滚(事务包裹),数据不会残留。对应 Laravel 的 RefreshDatabase 效果。

测试数据怎么造 ​

JPA 测试没有 Laravel 的 Factory,两个选择:

1. 测试里手动 new + save(上面的例子,简单直接)

2. 用共享 @BeforeEach 造数据:

java
@BeforeEach
void setUp() {
    postRepository.saveAll(List.of(
            post("帖子1", 1),
            post("帖子2", 1),
            post("帖子3", 0)));
}

TIP

想要 Laravel 那样的 Factory(自动生成一堆测试数据),可用 easy-random 或 instancio 库随机填充实体字段,但大多数测试手写几条就够。

方案二:@MybatisTest(MyBatis 层测试) ​

MyBatis 对应 @DataJpaTest 的注解是 @MybatisTest(mybatis-spring-boot-starter-test):

java
@MybatisTest
class PostMapperTest {

    @Autowired
    private PostMapper postMapper;

    @Test
    void 插入后能查到() {
        Post post = new Post();
        post.setTitle("测试");
        post.setStatus(1);
        postMapper.insert(post);

        assertNotNull(post.getId());               // 主键回填
        Post found = postMapper.findById(post.getId());
        assertEquals("测试", found.getTitle());
    }
}

TIP

@MybatisTest 需要 @AutoConfigureTestDatabase(replace = Replace.NONE) 配合实际数据源,或直接用 H2 + 内存库。它和 @DataJpaTest 一样是「切片测试」:只加载数据访问层。

方案三:Testcontainers(真实数据库,最可靠) ​

H2 兼容 MySQL 大多数语法,但总有差异(JSON 类型、窗口函数、特殊索引)。要 100% 贴近生产,用 Testcontainers 起真实 MySQL 容器:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-testcontainers</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>mysql</artifactId>
    <scope>test</scope>
</dependency>
java
@Testcontainers
@SpringBootTest
class PostRepositoryIntegrationTest {

    @Container
    static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0");

    @DynamicPropertySource
    static void datasourceProps(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", mysql::getJdbcUrl);
        registry.add("spring.datasource.username", mysql::getUsername);
        registry.add("spring.datasource.password", mysql::getPassword);
    }

    @Autowired
    private PostRepository postRepository;

    @Test
    void 真实MySQL上CRUD() {
        Post post = new Post();
        post.setTitle("真实库测试");
        postRepository.save(post);
        assertNotNull(post.getId());
    }
}

TIP

@Testcontainers + @Container 自动管理容器生命周期(起库、测试、销毁)。配合 Flyway 自动迁移,每个测试跑在「生产一致」的 schema 上,是最可信的数据库测试。

覆盖普通数据访问测试的常见断言 ​

java
// 事务回滚生效
@Test
void 事务异常回滚() {
    assertThrows(RuntimeException.class, () -> {
        service.transfer(1L, 2L, BigDecimal.TEN);   // 内部抛异常
    });
    // 断言两个账户余额都没变
}

// 分页
@Test
void 分页查询() {
    Page<Post> page = postRepository.findAll(
            PageRequest.of(0, 2));
    assertEquals(2, page.getContent().size());
}

方案选型总结 ​

场景用什么
JPA 层逻辑(方法名查询、@Query)@DataJpaTest + H2(快)
MyBatis 层逻辑(XML SQL)@MybatisTest + H2
复杂 SQL、数据库专属语法Testcontainers 真实库
完整请求链路(Controller→DB)@SpringBootTest + H2 或 Testcontainers
只测 Controller,不碰库@WebMvcTest + Mock 掉 Service

三句话原则

  1. 测试库隔离:H2 内存库 或 Testcontainers,绝不碰开发/生产库
  2. 先切片:能 @DataJpaTest 就别 @SpringBootTest(快 10 倍)
  3. Flyway 建 schema:测试环境也用迁移建表,和生产一致

下一节:模拟对象(Mockito)。

面向 PHP / Laravel 开发者的 Spring Boot 中文文档