如今,在软件开发中,单元测试非常重要,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<Tutorial, Long> { List<Tutorial> findByPublished(boolean published); List<Tutorial> 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文件并添加以下依赖项:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency>
定义数据模型
在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<Tutorial, Long> { List<Tutorial> findByPublished(boolean published); List<Tutorial> findByTitleContaining(String title); }
现在我们可以使用JpaRepository的方法:save()、findOne()、findById()、findAll()、count()、delete()、deleteById()...,而无需实现这些方法。
我们还定义了自定义的查找方法:
`findByPublished()`:返回所有published字段值为输入参数published的教程。
`findByTitleContaining()`:返回标题中包含输入参数title的所有教程。
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(); } }
运行单元测试
首先运行命令:`mvn clean install`
然后运行测试:`mvn test`
[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] -------------
或者您也可以以JUnit测试模式运行Spring Boot项目。
现在查看JUnit测试结果如下所示:
文章来源: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模板网!