@DataJpaTest 和 Repository 类在 JUnit 中
最后更新:2024 年 2 月 28 日
1. 简介
在使用 Spring Data JPA 进行数据持久化的 Spring Boot 应用程序中,测试与数据库交互的存储库至关重要。在本教程中,我们将探讨如何使用 Spring Boot 提供的 @DataJpaTest 注解以及 JUnit 有效地测试 Spring Data JPA 存储库。
2. 理解 @DataJpaTest 和 Repository 类
在本节中,我们将深入研究 @DataJpaTest 和 Spring Boot 应用程序中的类存储库之间的交互。
2.1. @DataJpaTest
@DataJpaTest 注解用于测试 Spring Boot 应用程序中的 JPA 存储库。它是一种专门的测试注解,为测试持久层提供了一个最小的 Spring 上下文。 此注解可以与其他测试注解(如 @RunWith 和 @SpringBootTest)结合使用。
此外,@DataJpaTest 的范围仅限于应用程序的 JPA 存储库层。 它不会加载整个应用程序上下文,这可以使测试更快、更集中。 此注解还提供了一个预配置的 EntityManager 和 TestEntityManager 用于测试 JPA 实体。
2.2. Repository 类
在 Spring Data JPA 中,存储库是对 JPA 实体的一种抽象层。它提供了一组执行 CRUD(创建、读取、更新、删除)操作和执行自定义查询的方法。 这些存储库通常从像 JpaRepository 这样的接口扩展而来,负责处理与特定实体类型相关的数据库交互。
3. 可选参数
@DataJpaTest 具有一些可选参数,我们可以使用它们来定制测试环境。
3.1. properties
此参数允许我们指定将应用于测试上下文的 Spring Boot 配置属性。 这对于调整数据库连接详细信息、事务行为或其他与测试需求相关的应用程序属性而言非常有用。
@DataJpaTest(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.jpa.hibernate.ddl-auto=create-drop"
})
public class UserRepositoryTest {
// ... test methods
}
3.2. showSql
这启用了我们的测试的 SQL 日志记录,并允许我们查看存储库方法执行的实际 SQL 查询。 此外,这有助于调试或了解 JPA 查询的转换方式。 默认情况下,SQL 日志记录已启用。 我们可以通过将值设置为 false 来关闭它
@DataJpaTest(showSql = false)
public class UserRepositoryTest {
// ... test methods
}
3.3. includeFilters 和 excludeFilters
这些参数使我们能够在组件扫描期间包含或排除特定组件。 我们可以使用它们来缩小扫描范围并优化测试性能,仅关注相关的组件
@DataJpaTest(includeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserRepository.class),
excludeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = SomeIrrelevantRepository.class))
public class UserRepositoryTest {
// ... test methods
}
4. 关键特性
在测试 Spring Boot 应用程序中的 JPA 存储库时,@DataJpaTest 注解可能是一个方便的工具。 让我们详细探讨其关键特性和优势。
4.1. 测试环境配置
为 JPA 存储库设置适当的测试环境可能既耗时又棘手。 @DataJpaTest 提供了一个现成的测试环境,其中包含测试 JPA 存储库所需的关键组件,例如 EntityManager 和 DataSource。
此环境专为测试 JPA 存储库而设计。 它确保我们的存储库方法在测试事务的上下文中运行,与安全的内存数据库(如 H2)交互,而不是生产数据库。
4.2. 依赖注入
@DataJpaTest 简化了测试类中的依赖注入过程。 存储库以及其他基本 bean 会自动注入到测试上下文中。 这种无缝集成使开发人员能够专注于编写简洁有效的测试用例,而无需进行显式 bean 接线。
4.3. 默认回滚
此外,保持测试的独立性和可靠性至关重要。默认情况下,每个使用 @DataJpaTest 注解的测试方法都在事务边界内运行。 这确保了对数据库所做的更改会在测试结束时自动回滚,为下一个测试留下一个干净的状态。
5. 配置和设置
要使用 @DataJpaTest,我们需要将 spring-boot-starter-test 依赖项添加到我们的项目中,scope 为“test”。这个轻量级依赖项包含 JUnit 等必要的测试库,用于测试,确保它不包含在我们的生产构建中。
5.1. 将依赖项添加到 pom.xml
让我们将以下依赖项添加到 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
一旦添加了依赖项,我们就可以在测试中使用 @DataJpaTest 注解。这个注解会为我们设置一个内存中的 H2 数据库并配置 Spring Data JPA,允许我们编写与我们的仓库类交互的测试。
5.2. 创建实体类
现在,让我们创建 User 实体类,它将代表用户数据
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
// getters and setters
}
5.3. 创建仓库接口
接下来,我们定义 UserRepository,一个用于管理 User 实体的 Spring Data JPA 仓库接口
public interface UserRepository extends JpaRepository<User, Long> {
// Add custom methods if needed
}
通过扩展 JpaRepository<User, Long>,我们的 UserRepository 可以直接访问 Spring Data JPA 提供的标准 CRUD 操作。
此外,我们可以在此接口中定义自定义查询方法,以满足特定的数据访问检索需求,例如 findByUsername()
public interface UserRepository extends JpaRepository<User, Long> {
// Custom query method to find a user by username
User findByUsername(String username);
}
6. 实现仓库测试
为了测试应用程序的仓库层,我们将使用 @DataJpaTest 注解。 通过使用这个注解,一个内存中的 H2 数据库将被设置,并且 Spring Data JPA 将被配置。 这允许我们编写与我们的仓库类交互的测试。
6.1. 设置测试类
首先,让我们通过使用 @DataJpaTest 注解来设置测试类。这个注解会扫描带有 @Entity 注解的实体类和 Spring Data JPA 仓库接口。这确保了只有相关的组件被加载进行测试,从而提高了测试的重点和性能
@DataJpaTest
public class UserRepositoryTest {
// Add test methods here
}
要创建一个仓库测试用例,我们首先需要将我们想要测试的仓库注入到我们的测试类中。这可以使用 @Autowired 注解完成
@Autowired
private UserRepository userRepository;
6.2. 测试生命周期管理
在测试生命周期管理方面,@BeforeEach 和 @AfterEach 注解用于在每个测试方法执行之前和之后执行设置和清理操作。 这确保了每个测试方法都在一个干净且隔离的环境中运行,具有一致的初始条件和清理程序。
以下是我们如何在测试类中结合测试生命周期管理
private User testUser;
@BeforeEach
public void setUp() {
// Initialize test data before each test method
testUser = new User();
testUser.setUsername("testuser");
testUser.setPassword("password");
userRepository.save(testUser);
}
@AfterEach
public void tearDown() {
// Release test data after each test method
userRepository.delete(testUser);
}
在带有 @BeforeEach 注解的 setUp() 方法中,我们可以执行每个测试方法执行之前所需的任何必要的设置操作。这可能包括初始化测试数据、设置模拟对象或准备测试所需的资源。
相反,在带有 @AfterEach 注解的 tearDown() 方法中,我们可以在每个测试方法执行后执行清理操作。这可能涉及重置在测试期间所做的任何更改、释放资源或执行任何必要的清理任务以将测试环境恢复到其原始状态。
6.3. 测试插入操作
现在,我们可以编写与 JPA 仓库交互的测试方法。例如,我们可能想要测试是否可以将新用户保存到数据库中。由于用户在每个测试之前都会自动保存,因此我们可以直接专注于测试与 JPA 仓库的交互。
@Test
void givenUser_whenSaved_thenCanBeFoundById() {
User savedUser = userRepository.findById(testUser.getId()).orElse(null);
assertNotNull(savedUser);
assertEquals(testUser.getUsername(), savedUser.getUsername());
assertEquals(testUser.getPassword(), savedUser.getPassword());
}
如果我们观察测试案例的控制台日志,我们会注意到以下日志
Began transaction (1) for test context
.....
Rolled back transaction for test:
这些日志表明@BeforeEach 和 @AfterEach 方法按预期工作。
6.4. 测试更新操作
此外,我们可以创建一个测试案例来测试更新操作
@Test
void givenUser_whenUpdated_thenCanBeFoundByIdWithUpdatedData() {
testUser.setUsername("updatedUsername");
userRepository.save(testUser);
User updatedUser = userRepository.findById(testUser.getId()).orElse(null);
assertNotNull(updatedUser);
assertEquals("updatedUsername", updatedUser.getUsername());
}
6.5. 测试 findByUsername() 方法
现在,让我们测试我们创建的 findByUsername() 自定义查询方法
@Test
void givenUser_whenFindByUsernameCalled_thenUserIsFound() {
User foundUser = userRepository.findByUsername("testuser");
assertNotNull(foundUser);
assertEquals("testuser", foundUser.getUsername());
}
7. 事务行为
默认情况下,所有带有 @DataJpaTest 注解的测试都在一个事务中执行。 这意味着在测试期间对数据库所做的任何更改都会在测试结束时回滚,从而确保数据库保持其原始状态。 这种默认行为简化了测试,防止测试之间的干扰和数据损坏。
然而,在某些情况下,我们可能需要禁用事务行为来测试某些场景。例如,测试结果可能需要在测试结束后持久保存。
在这种情况下,我们可以使用 @Transactional 注解,并将 propagation 设置为 propagation.NOT_SUPPORTED,来禁用特定测试类的事务。
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class UserRepositoryIntegrationTest {
// ... test methods
}
或者我们可以为单个测试方法禁用事务
@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testMyMethodWithoutTransactions() {
// ... code that modifies the database
}
8. 结论
在本文中,我们学习了如何在 JUnit 中使用 @DataJpaTest 来测试我们的 JPA 仓库。总的来说,@DataJpaTest 是一个强大的注解,用于在 Spring Boot 应用程序中测试 JPA 仓库。它提供了一个专注的测试环境和预配置的工具来测试持久层。通过使用 @DataJpaTest,我们可以确保我们的 JPA 仓库正常工作,而无需启动整个 Spring 上下文。
支持本文的代码可在 GitHub 上获取。 一旦你以 Baeldung Pro 会员 身份登录,就开始学习并在项目上进行编码。















