@DataJpaTest的Spring Data Repository单元测试示例

如今,在软件开发中,单元测试非常重要,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项目:

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测试结果如下所示:

JUnit测试结果

总结

今天我们使用JUnit 5和@DataJPATest以及TestEntityManager与H2数据库创建了一个针对JPA Repository的Spring Boot测试。我们还对许多CRUD操作和自定义查找方法进行了单元测试。文章来源地址https://www.toymoban.com/diary/java/699.html

到此这篇关于@DataJpaTest的Spring Data Repository单元测试示例的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.toymoban.com/diary/java/699.html

如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用
Spring Boot中的自定义查询示例:使用Spring JPA @Query
上一篇 2024年01月21日 01:23
使用js实现计算运行时间,并且精确到天时分秒
下一篇 2024年01月24日 17:14

相关文章

  • 【单元测试】Spring Data JPA + H2 测试DAO层

    Springboot 2.7.8 h2 2.1.214 引入springboot parent pom 点击查看代码 引入junit , springboot-test, spring-data-jpa, H2 点击查看代码 H2是一款内存数据库,可以配合单测测试数据层。实现原理是将依赖的三方数据库通过内存的方式进行mock。其中H2数据库的数据表结构以及数据可以通过sql脚本文件初

    2024年02月07日
    浏览(99)
  • Spring Data JPA 学习笔记

    Spring Data JPA: Spring Data JPA 的技术特点: @Entity 标注是一个实体类,实体类中的每一个属性都对应表中的一列。 @Table(name = “User”) 这个注解用于指定实体类对应的数据库表名。(但首字母会小写) @Data:这个注解是Lombok库提供的,用于自动生成实体类的getter和setter方法、构造函

    2024年04月09日
    浏览(54)
  • Spring Data JPA 快速上手

    JPA的全称是Java Persisitence API,即JAVA持久化API,是sum公司退出的一套基于ORM的规范,内部是由一些列的接口和抽象类构成。JPA通过JDK5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 Spring Data的优势:可以操作多种数据库,关系型数据库,非关系

    2024年04月23日
    浏览(43)
  • Spring data JPA常用命令

    Spring Data JPA是Spring框架的一部分,它提供了一个简化的方式来与关系型数据库进行交互。JPA代表Java持久化API,它是Java EE规范中定义的一种对象关系映射(ORM)标准。Spring Data JPA在JPA的基础上提供了更高级的抽象,使得开发人员能够更轻松地进行数据库操作。 使用Spring Data

    2024年02月15日
    浏览(55)
  • Spring Boot整合Spring Data Jpa + QueryDSL

    Spring Data JPA是一个Spring项目中常用的持久化框架,它简化了与数据库进行交互的过程。而QueryDSL是一个查询构建框架,可以让我们以面向对象的方式来编写数据库查询。 在本文中,我们将讨论如何使用Spring Boot整合Spring Data JPA和QueryDSL,并提供一个使用案例来演示它们的用法。

    2024年02月09日
    浏览(64)
  • Spring Data JPA的@Entity注解

     rulesCouponTypeConverter.java  entity/CouponTemplate.java Spring JPA 包的标准注解,对数据库字段进行了映射,我挑几个关键注解说道一下。 1、Entity:声明了“数据库实体”对象,它是数据库 Table 在程序中的映射对象; 2、Table:指定了 CouponTemplate 对应的数据库表的名称; 3、ID/Generat

    2024年02月11日
    浏览(57)
  • Springboot --- 整合spring-data-jpa和spring-data-elasticsearch

    SpringBoot: 整合Ldap. SpringBoot: 整合Spring Data JPA. SpringBoot: 整合Elasticsearch. SpringBoot: 整合spring-data-jpa和spring-data-elasticsearch. SpringBoot: 整合thymeleaf. SpringBoot: 注入第三方jar包. SpringBoot: 整合Redis. SpringBoot: 整合slf4j打印日志. SpringBoot: 整合定时任务,自动执行方法. SpringBoot: 配置多数据源

    2023年04月25日
    浏览(74)
  • Spring Boot 篇四: Spring Data JPA使用SQL Server

    本篇介绍篇一至篇三中用到的JPA链接SQL Server的具体情况以及实战过程中可能遇到的问题。 具体的下载和安装教程,请参阅微软SQL Server官网; SQL Server Express 是免费的,并且配套的SQL Server Management Studio也是可以用的。 呃,当然,使用Docker来运行SQL Server是另外一条路径。具体

    2024年02月05日
    浏览(97)
  • 如何使用Spring Data JPA简化MySQL数据访问

    本篇文章是 “一起学习mysql” 系列的第五篇文章,本篇文章我们学习一下Spring Data JPA的使用,在开始学习器,我们先来了解一下什么是JPA。 JPA的全称是Java Persistence API,是J2EE中的一条规范,它标准化了数据持久化API。在上一篇文章中,我们了解了如何使用MyBatis进行MySQL数据

    2024年02月15日
    浏览(70)
  • Spring Data JPA之自动创建数据库表

    由于在项目中使用到了Spring Data JPA(Java Persistent API)进行项目开发,并且自己对JPA比较感兴趣想进行学习和了解。首先学习和了解的是JPA自动创建数据库表,通过JPA能够让软件工程师们不用再去手动创建数据表,能够减轻软件工程师们的工作量。 通过本篇博客可以实现使用

    2024年02月05日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包