测试持久层:Spring Boot + @DataJpaTest+H2 mem+Junit5

基本概念:

   JPA是Java Persistence API的简称,中文名Java持久层API 

     是Sun官方在JDK5.0后提出的Java持久化规范, hibernate实现了这个规范,比mybais有优势

测试持久层目的:就是为了验证数据表创建,查询等,所以不用在mysql等数据库验证

总结

   在这个位置停留了很久

   原因1:

    坚持使用h2 三种模式之一的内存mem模式,也获得了url

url:jdbc:h2:mem:musicbird;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MYSQL

该url可以在idea打开,但是测试文件运行之后数据表就是不出来,

h2 mem比较特别,连接了数据库即创建出来

   测试持久层:Spring Boot + @DataJpaTest+H2 mem+Junit5_第1张图片

 最后也没有在这个界面上看到创建出来的表,而是通过使用repository中的

User2 getByUsername(String username)获得查询返回

 

收获1:entity中的实体名字尽量不要叫user,这是H2数据库的保留关键字

             否则会报错:Syntax error in SQL statement,也许有其他方法解决

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table [*]User (Id varchar(255) not null, created_time timestamp, updated_time timestamp, avatar varchar(255), email varchar(255), enabled boolean, gender varchar(255), last_login_ip varchar(255), last_login_time timestamp, locked boolean, mobile varchar(255), nickname varchar(255), password varchar(255), true_name varchar(255), username varchar(255), primary key (Id))"; expected "identifier"; SQL statement:
create table User (Id varchar(255) not null, created_time timestamp, updated_time timestamp, avatar varchar(255), email varchar(255), enabled boolean, gender varchar(255), last_login_ip varchar(255), last_login_t

收获2:

     测试不用flyway,主要是没必要,因为hibernet会自动依照entity中的内容生成数据表

里面的create语句不是我写的

Hibernate: drop table if exists user_all
Hibernate: create table user_all (id varchar(255) not null, created_time datetime, updated_time datetime, avatar varchar(255), email varchar(255), enabled bit, gender varchar(255), last_login_ip varchar(255), last_login_time datetime, locked bit, mobile varchar(255), nickname varchar(255), password varchar(255), true_name varchar(255), user

      在test下application.properties把flyway设置为false

测试方法简述:

     1)编写entity-->编写repository-->

       在比如UserRepository中Generate 测试文件

     2)测试文件会在test目录下

     测试持久层:Spring Boot + @DataJpaTest+H2 mem+Junit5_第2张图片

Step1:修改test/resources下的application.properties

   注意修改其application.properties以完成实现把h2数据库配置到其中

#---------服务器配置-----------
server.port=8080
#---------数据源配置-----------
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:musicbird;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MYSQL
spring.datasource.username=root
spring.datasource.password=123456
spring.sql.init.platform=h2

#SQL脚本编码
spring.sql.init.encoding=UTF-8
spring.sql.init.platorm=h2
#初始化模式
spring.sql.init.mode=always
#如果在初始化数据库时发生错误,是否停止
spring.sql.init.continue-on-error=false

#----------flyway配置--------------
spring.flyway.enabled=false
#---------JPA配置-------------
#要操作的目标数据库
spring.jpa.database=h2
#控制台显示SQL语句
spring.jpa.show-sql=true
#更新或者创建数据表结构
spring.jpa.hibernate.ddl-auto=update
#物理命名策略的完全限定名称
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#是否在启动时初始化架构
spring.jpa.generate-ddl=true
logging.level.org.hibernate=DEBUG
#----------H2配置--------------
spring.h2.console.path=/h2-console
#启用控制台
spring.h2.console.enabled=true

 Step2:编写Entity

里面的@Entity特别重要,每个entity都要有id,统一写在其父类里面了

测试持久层:Spring Boot + @DataJpaTest+H2 mem+Junit5_第3张图片

 

package com.i7i8i9.musicbird1.entity;

import com.i7i8i9.musicbird1.enums.Gender;
import lombok.Data;

import javax.persistence.*;
import java.util.Date;

@Entity
@Data
public class User2 extends AbstractEntity{ //entity会自动映射到数据库

    private  String username;
    private  String password;
    @Enumerated(EnumType.STRING)
    private Gender gender; //因为已经定义在了enums里面,默认存储0,1,2,上面@内容表示取其内容,以便于存储在数据库
    private  String email;
    private  String avatar;
    private  String mobile;
    private  String nickname;
    private  String true_name;
    private  Boolean locked;
    private  Boolean enabled;
    private  String last_login_ip;
    private Date last_login_time;


}

父类

package com.i7i8i9.musicbird1.entity;

import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.util.Date;

@MappedSuperclass    //这个是让其他类能够继承id,好像可以不加,有的不加子类报错
@Data
public abstract class AbstractEntity {

    @javax.persistence.Id    //这个是自动生成的,或许可以直接用@Id
    @GeneratedValue(generator = "ksuid")
    @GenericGenerator(name="ksuid",strategy = "com.i7i8i9.musicbird1.utils.KsuidIdentifierGenerator")
    private  String Id;//Id新建时候会自东调用上面的类,把值塞进去
    @CreationTimestamp  //hibernate 表示创建时候更新
    private Date created_time;
    @UpdateTimestamp
    private  Date  updated_time;
}

 Step3:编写reposity

测试持久层:Spring Boot + @DataJpaTest+H2 mem+Junit5_第4张图片

 

package com.i7i8i9.musicbird1.repository;

import com.i7i8i9.musicbird1.entity.User2;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository {//User指的是entity中的user string 指的是id

   // default List findByUsername(String username) {
    //    return findByUsername(username);
   // }
    User2 getByUsername(String username);

}

 Step4:编写测试文件

  可以在repository文件上右键generate生成

里面的 三个必须,其余未研究

@DataJpaTest  说明这是在测试数据库操作
   @Autowired   @Test
package com.i7i8i9.musicbird1.repository;

import com.i7i8i9.musicbird1.entity.User2;
import com.i7i8i9.musicbird1.enums.Gender;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.annotation.Commit;
import org.springframework.test.context.ActiveProfiles;

import java.util.Date;

// @ActiveProfiles("dev")  指定是不是使用application-dev.properties
@DataJpaTest   //持久层测试必须写这个
//@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) //还是没有用指定数据库
class UserRepositoryTest {
    @Autowired   //用于生成对象,有多少个对象就要在其上面写多少次
    UserRepository repository;
    @Test     //测试文件自动生成的
    @Commit   //主要是不回滚,实际测试估计不用设置本项
    void findByUsername() {
        User2 user=new User2();
        user.setUsername("libai");
        user.setNickname("小白");
        user.setPassword("123456");
        user.setGender(Gender.MALE);
        user.setEnabled(true);
        user.setLocked(false);
        user.setEmail("[email protected]");
        user.setLast_login_ip("127.0.0.1");
        user.setLast_login_time(new Date());
        //存储到数据库,会返回user
        User2 saveUser=repository.save(user);
        System.out.println(saveUser.toString());
        System.out.println("测试结束");

        User2 result=repository.getByUsername("libai");
        System.out.println("hello"+result.toString());
    }
}

 Step5:运行测试文件

Process finished with exit code 0代表成功

点击左边下面的方法,可以过滤看到创建和查询结果

测试持久层:Spring Boot + @DataJpaTest+H2 mem+Junit5_第5张图片

 

1)确认配置

   pom中引入了jpa


            org.springframework.boot
            spring-boot-starter-data-jpa
        

 

其他

1)配置

@DataJpaTest 会配置 Hibernate 为我们自动创建数据库模式。对此负责的属性是 spring.jpa.hibernate.ddl-auto,Spring Boot 默认将其设置为 create-drop,这意味着模式在运行测试之前创建并在测试执行后删除。

   

Spring Data Jpa的使用_^LiuYttt的博客-CSDN博客_springdatajpa的使用

hibernate在springboot中简单使用_薄荷味脑花的博客-CSDN博客_springboot hibernate

【报错1】java.lang.NullPointerException: Cannot invoke "com.i7i8i9.musicbird1.repository.UserRepository.save(Object)" because "this.repository" is null

    ->需要在任何为空的前面加 @Autowired,

    ->如果有两行就要加两个

class UserRepositoryTest {
    @Autowired   //将类引入变量
    UserRepository repository;//引入UserRepository,为了测试
    @Test
    void findByUsername() {

【报错2】No qualifying bean of type 'com.i7i8i9.musicbird1.repository.UserRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

因为我们要测的是数据库,所以使用

为了测试 Spring Data JPA 存储库或任何其他与 JPA 相关的组件,Spring Boot 提供了 @DataJpaTest 注解。我们可以将它添加到单元测试中,它将设置一个 Spring 应用程序上下文:

@DataJpaTest
class UserRepositoryTest {
    @Autowired
    UserRepository repository;
    @Test
    void findByUsername() {

测试

SpringBoot——单元测试之JUnit5_宋子浩的博客-CSDN博客_junit5测试springboot

Java测试框架-junit5详解_小测.的博客-CSDN博客_junit5

 @SpringBootTest注解:添加在需要依赖springboot框架的测试类上,

                                        不然不能使用Springboot的相关开发功能

@Test注解:添加在测试方法上

FlyWay在yml中配置

1)如果未设置属性,则Spring Boot将使用主DataSource或(如果存在)注释为@FlywayDataSource的DataSource配置Flyway。属性spring.flyway.url的存在是为了用一个具体的连接字符串覆盖这个选择过程。相关代码可以在类FlywayAutoConfiguration中找到。

在H2的特定情况下,重写连接字符串会导致这样一个问题,即H2数据库在事务之后不会保持打开状态,除非连接字符串包含指示它这样做的标志。这解释了问题中的观察结果,即Flyway运行的数据库随后关闭,然后Hibernate连接到一个干净的新H2实例。

在H2的特定情况下,重写连接字符串会导致这样一个问题,即H2数据库在事务之后不会保持打开状态,除非连接字符串包含指示它这样做的标志。这解释了问题中的观察结果,即Flyway运行的数据库随后关闭,然后Hibernate连接到一个干净的新H2实例。

这遵循了Spring Boot的通常模式及其auto-configuration的哲学。Auto-configuration旨在hands-off工作,并且仅由类路径上的事物触发。因此,对于其许多功能,无需属性或代码即可启用它们。

同时,Spring Boot只能对auto-configuration在何种情况下应配置的内容使用合理的默认值或启发式。因此,Spring Boot带有扩展点和标志,如果auto-configuration做得不对,可以轻松地退出。属性spring.flyway.url是这些标志之一。

JPA

这个也很重要,在yml中的配置:

如果不配成create

jpa:
  hibernate:
    ddl-auto: create 

ddl-auto:update----每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新

ddl-auto:validate----运行程序会校验数据与数据库的字段类型是否相同,不同会报错

ddl-auto:create----每次运行该程序,没有表格会新建表格,表内有数据会清空

ddl-auto:create-drop----每次程序结束的时候会清空表
 

你可能感兴趣的:(JDK,java,spring,spring,boot)