共计 10267 个字符,预计需要花费 26 分钟才能阅读完成。
如今,在软件开发中,单元测试非常重要,Spring 框架也提供了 @DataJpaTest 注解,使得编写 JPA Repository 的测试更加简单。在本教程中,我们将学习如何在 Spring Boot 项目中应用 @DataJpaTest,并结合 TestEntityManager 和 JUnit 5 进行运行。
Spring Boot @DataJpaTest 示例概述
我们有一个 Tutorial 模型,包含一些字段:id、title、description、published。
有一个用于与数据库交互的存储库,名为 TutorialRepository 接口,它扩展了 JpaRepository:
public interface TutorialRepository extends JpaRepository {List findByPublished(boolean published);
List findByTitleContaining(String title);
}
JpaRepository 还支持以下方法:save()、findOne()、findById()、findAll()、count()、delete()、deleteById()。
那么如何为它们编写单元测试呢?
=> 我们将使用 @DataJpaTest 和 TestEntityManager 来进行测试。
@RunWith(SpringRunner.class)
@DataJpaTest
public class JPAUnitTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
TutorialRepository repository;
@Test
public void should_find_no_tutorials_if_repository_is_empty() {}
@Test
public void should_store_a_tutorial() {}
@Test
public void should_find_all_tutorials() {}
@Test
public void should_find_tutorial_by_id() {}
@Test
public void should_find_published_tutorials() {}
@Test
public void should_find_tutorials_by_title_containing_string() {}
@Test
public void should_update_tutorial_by_id() {}
@Test
public void should_delete_tutorial_by_id() {}
@Test
public void should_delete_all_tutorials() {}
}
对于测试,我们将使用 H2 内存数据库。它消除了配置和启动实际数据库的需要。
@DataJpaTest 注解用于测试 JPA Repository
@DataJpaTest 是 Spring 支持的专注于 JPA 组件的 JPA 测试注解。
它将禁用完整的自动配置,然后仅应用与 JPA 测试相关的启用配置。可以在此处找到启用的自动配置设置列表。
默认情况下,使用 @DataJpaTest 注解的测试是事务性的,并且在每个测试结束时进行回滚。如果不希望这样,可以使用 @Transactional 注解禁用测试或整个类的事务管理:
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class YourNonTransactionalTests {}
内存嵌入式数据库(如本示例中的 H2 数据库)通常对测试效果良好,它运行速度快,不需要任何安装。然而,我们可以通过 @AutoConfigureTestDatabase 注解来配置真实数据库:
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
class YourRepositoryTests {}
如果使用 JUnit 4,则需要在测试中添加 @RunWith(SpringRunner.class):
@RunWith(SpringRunner.class)
@DataJpaTest
class YourRepositoryTests {}
TestEntityManager
EntityManager 的目的是与持久化上下文进行交互。Spring Data JPA 通过 Repository 接口将您从 EntityManager 中抽象出来。而 TestEntityManager 允许我们在测试中使用 EntityManager。
我们可以在 Data JPA 测试中注入一个 TestEntityManager bean。如果您想在 @DataJpaTest 实例之外使用 TestEntityManager,只需添加 @AutoConfigureTestEntityManager 注解。
以下示例展示了带有 TestEntityManager 的 @DataJpaTest 注解:
@DataJpaTest
class YourRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Test
void testExample() throws Exception {this.entityManager.persist(new Tutorial("Tut#1", "Desc#1", true));
...
}
}
在这个示例中,TestEntityManager 被注入并可以在测试方法中使用,以进行与实际数据库的交互和操作。
项目结构
让我们来看一下我们的 Spring Boot 项目:
-
Tutorial 数据模型类对应于实体和名为 ”tutorials” 的表。
-
TutorialRepository 是一个接口,它扩展了 JpaRepository,提供了 CRUD 方法和自定义查找方法。它将在 JPAUnitTest 中被自动装配(Autowired)使用。
-
JPAUnitTest 是主要的测试类,用于测试 JPA,并使用 @DataJpaTest 注解进行标记。
-
pom.xml 包含了 Spring Boot、JPA 和 H2 数据库的依赖项。
搭建 Spring Boot @DataJpaTest 项目
使用 Spring Web 工具或你的开发工具(如 Spring Tool Suite、Eclipse、Intellij)创建一个 Spring Boot 项目。
然后打开 pom.xml 文件并添加以下依赖项:
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-test
test
com.h2database
h2
test
定义数据模型
在 model 包中,我们定义 Tutorial 类。
我们的数据模型(实体)包含 4 个字段:id、title、description、published。
model/Tutorial.java
package com.bezkoder.spring.data.jpa.test.model;
import javax.persistence.*;
@Entity
@Table(name = "tutorials")
public class Tutorial {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "title")
private String title;
@Column(name = "description")
private String description;
@Column(name = "published")
private boolean published;
public Tutorial() {}
public Tutorial(String title, String description, boolean published) {
this.title = title;
this.description = description;
this.published = published;
}
// getters and setters
@Override
public String toString() {return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
}
}
-
`@Entity` 注解指示该类是一个持久化的 Java 类。
-
`@Table` 注解提供了映射到该实体的表名。
-
`@Id` 注解用于主键。
-
`@GeneratedValue` 注解用于定义主键的生成策略。GenerationType.AUTO 表示自动递增字段。
-
`@Column` 注解用于定义数据库中映射的列。
以上是 Tutorial 类的代码,它定义了数据模型的结构和属性,并提供了必要的方法和注解来与数据库进行映射和交互。
创建 JPA Repository
在 repository 包中,创建一个 TutorialRepository 接口,它扩展了 JpaRepository。这个存储库将与数据库中的 Tutorials 进行交互。
repository/TutorialRepository.java
package com.bezkoder.spring.data.jpa.test.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.bezkoder.spring.data.jpa.test.model.Tutorial;
public interface TutorialRepository extends JpaRepository {List findByPublished(boolean published);
List findByTitleContaining(String title);
}
现在我们可以使用 JpaRepository 的方法:save()、findOne()、findById()、findAll()、count()、delete()、deleteById()…,而无需实现这些方法。
我们还定义了自定义的查找方法:
Spring Data JPA 会自动提供实现。
使用 @Query 注解进行自定义查询的示例:
Spring Boot 中的自定义查询示例:使用 Spring JPA @Query
你也可以修改这个存储库以支持分页,相关指南可以在下面找到:
– [Spring Boot 分页和过滤器示例 | Spring JPA,Pageable](https://www.bezkoder.com/spring-boot-pagination-filter-jpa-pageable/)
使用 @DataJpaTest 编写单元测试
在 src/test/java 下创建一个名为 JPAUnitTest 的类,继承它。我们将在这个类中测试多种情况(CRUD 操作、查找方法)。
package com.bezkoder.spring.data.jpa.test;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import com.bezkoder.spring.data.jpa.test.model.Tutorial;
import com.bezkoder.spring.data.jpa.test.repository.TutorialRepository;
@DataJpaTest
public class JPAUnitTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
TutorialRepository repository;
@Test
public void should_find_no_tutorials_if_repository_is_empty() {Iterable tutorials = repository.findAll();
assertThat(tutorials).isEmpty();}
@Test
public void should_store_a_tutorial() {Tutorial tutorial = repository.save(new Tutorial("Tut title", "Tut desc", true));
assertThat(tutorial).hasFieldOrPropertyWithValue("title", "Tut title");
assertThat(tutorial).hasFieldOrPropertyWithValue("description", "Tut desc");
assertThat(tutorial).hasFieldOrPropertyWithValue("published", true);
}
@Test
public void should_find_all_tutorials() {Tutorial tut1 = new Tutorial("Tut#1", "Desc#1", true);
entityManager.persist(tut1);
Tutorial tut2 = new Tutorial("Tut#2", "Desc#2", false);
entityManager.persist(tut2);
Tutorial tut3 = new Tutorial("Tut#3", "Desc#3", true);
entityManager.persist(tut3);
Iterable tutorials = repository.findAll();
assertThat(tutorials).hasSize(3).contains(tut1, tut2, tut3);
}
@Test
public void should_find_tutorial_by_id() {Tutorial tut1 = new Tutorial("Tut#1", "Desc#1", true);
entityManager.persist(tut1);
Tutorial tut2 = new Tutorial("Tut#2", "Desc#2", false);
entityManager.persist(tut2);
Tutorial foundTutorial = repository.findById(tut2.getId()).get();
assertThat(foundTutorial).isEqualTo(tut2);
}
@Test
public void should_find_published_tutorials() {Tutorial tut1 = new Tutorial("Tut#1", "Desc#1", true);
entityManager.persist(tut1);
Tutorial tut2 = new Tutorial("Tut#2", "Desc#2", false);
entityManager.persist(tut2);
Tutorial tut3 = new Tutorial("Tut#3", "Desc#3", true);
entityManager.persist(tut3);
Iterable tutorials = repository.findByPublished(true);
assertThat(tutorials).hasSize(2).contains(tut1, tut3);
}
@Test
public void should_find_tutorials_by_title_containing_string() {Tutorial tut1 = new Tutorial("Spring Boot Tut#1", "Desc#1", true);
entityManager.persist(tut1);
Tutorial tut2 = new Tutorial("Java Tut#2", "Desc#2", false);
entityManager.persist(tut2);
Tutorial tut3 = new Tutorial("Spring Data JPA Tut#3", "Desc#3", true);
entityManager.persist(tut3);
Iterable tutorials = repository.findByTitleContaining("ring");
assertThat(tutorials).hasSize(2).contains(tut1, tut3);
}
@Test
public void should_update_tutorial_by_id() {Tutorial tut1 = new Tutorial("Tut#1", "Desc#1", true);
entityManager.persist(tut1);
Tutorial tut2 = new Tutorial("Tut#2", "Desc#2", false);
entityManager.persist(tut2);
Tutorial updatedTut = new Tutorial("updated Tut#2", "updated Desc#2", true);
Tutorial tut = repository.findById(tut2.getId()).get();
tut.setTitle(updatedTut.getTitle());
tut.setDescription(updatedTut.getDescription());
tut.setPublished(updatedTut.isPublished());
repository.save(tut);
Tutorial checkTut = repository.findById(tut2.getId()).get();
assertThat(checkTut.getId()).isEqualTo(tut2.getId());
assertThat(checkTut.getTitle()).isEqualTo(updatedTut.getTitle());
assertThat(checkTut.getDescription()).isEqualTo(updatedTut.getDescription());
assertThat(checkTut.isPublished()).isEqualTo(updatedTut.isPublished());
}
@Test
public void should_delete_tutorial_by_id() {Tutorial tut1 = new Tutorial("Tut#1", "Desc#1", true);
entityManager.persist(tut1);
Tutorial tut2 = new Tutorial("Tut#2", "Desc#2", false);
entityManager.persist(tut2);
Tutorial tut3 = new Tutorial("Tut#3", "Desc#3", true);
entityManager.persist(tut3);
repository.deleteById(tut2.getId());
Iterable tutorials = repository.findAll();
assertThat(tutorials).hasSize(2).contains(tut1, tut3);
}
@Test
public void should_delete_all_tutorials() {entityManager.persist(new Tutorial("Tut#1", "Desc#1", true));
entityManager.persist(new Tutorial("Tut#2", "Desc#2", false));
repository.deleteAll();
assertThat(repository.findAll()).isEmpty();}
}
运行单元测试
[INFO] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.901 s - in com.bezkoder.spr
ing.data.jpa.test.JPAUnitTest
...
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 32.594 s
[INFO] Finished at: 2020-05-07T20:48:47+07:00
[INFO] -------------
文章来源:https://www.toymoban.com/diary/java/699.html
总结
今天我们使用 JUnit 5 和 @DataJPATest 以及 TestEntityManager 与 H2 数据库创建了一个针对 JPA Repository 的 Spring Boot 测试。我们还对许多 CRUD 操作和自定义查找方法进行了单元测试。 文章来源地址 https://www.toymoban.com/diary/java/699.html
到此这篇关于 @DataJpaTest 的 Spring Data Repository 单元测试示例的文章就介绍到这了, 更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持 TOY 模板网!