SpringBoot-3-数据访问&单元测试

文章目录

  • 1 数据访问
    • 1.1 SQL
      • 1.1.1 数据源自动配置
      • 1.1.2 使用Druid数据源
      • 1.1.3 整合Mybatis
    • 1.2 NoSQL
      • 1.2.1 SpringBoot整合Redis
      • 1.2.2 配置操作Redis
  • 2 单元测试
    • 2.1 Junit5简介
    • 2.2 Junit5常用注解
    • 2.3 断言
    • 2.4 前置条件
    • 2.5 参数化测试

1 数据访问

1.1 SQL

1.1.1 数据源自动配置

首先在pom中导入场景依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

该场景会自动引入数据源、jdbc、事务
接着需要根据业务需求导入对应的驱动
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
</dependency>

版本由spring-boot-starter-parent决定
需要注意使用的数据库版本和驱动版本对应

同样SpringBoot对jdbc场景做了默认配置
可以在spring-boot-autoconfigure中找到名为jdbc的包SpringBoot-3-数据访问&单元测试_第1张图片
常用的一些功能,在这里都有默认配置,如:

DataSourceAutoConfiguration: 数据源自动配置,默认使用Hikar
DataSourceTransactionManagerAutoConfiguration: 事务管理器自动配置
JdbcTemplateAutoConfiguration: jdbcTemplate自动配置 可以crud
...

在DataSourceAutoConfiguration中,配置如数据库连接池
如果自己没有配置DataSource和XADataSource,就会使用默认的数据库连接池
SpringBoot-3-数据访问&单元测试_第2张图片
再观察DataSourceAutoConfiguration类上的注解
SpringBoot-3-数据访问&单元测试_第3张图片
其中最重要的是@EnableConfigurationProperties注解
标明了自定义配置对应DataSourceProperties类
SpringBoot-3-数据访问&单元测试_第4张图片
DataSourceProperties类带有注解@ConfigurationProperties标明prefix属性
即可以在properties文件或yaml文件中通过spring.datasource属性来配置数据源一些属性
SpringBoot-3-数据访问&单元测试_第5张图片

1.1.2 使用Druid数据源

对于数据源,spring-boot-starter-data-jdbc默认使用Hikar作为数据源
Hikar有着高效的性能,但是国内开发大都采用阿里的Druid
Druid提供了一整套数据源的解决方案
在SpringBoot中想要使用Druid,有两种方式

一是在容器中创建Druid的Bean,有了自定义的DataSource,容器中就不会创建Hikar数据源

导入依赖:
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid</artifactId>
   <version>1.2.7</version>
</dependency>

数据源配置:
@Configuration(proxyBeanMethods = true)
public class MyDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        return dataSource;
    }
}

yaml配置:
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db_books
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

另一是使用专用的starter

引入druid-strater:
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.5</version>
</dependency>

druid扩展配置也可以由spring.datasource绑定
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db_books
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

    druid:
      filters: stat,wall
      # 配置druid的监控页面功能
      stat-view-servlet:
        enabled: true
        login-username: root
        login-password: 123456
        reset-enable: false

      # web监控配置
      web-stat-filter:
        enabled: true
        url-pattern: /*  
...      

1.1.3 整合Mybatis

开发中常用Mybatis而不是JdbcTemplate,需要整合到SpringBoot中
首先需要导入对应的starter

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

在starter导入的mybatis-spring-boot-autoconfigure中的MybatisAutoConfiguration类上
SpringBoot-3-数据访问&单元测试_第6张图片
@EnableConfigurationProperties注解对应的绑定了MybatisProperties类
为此可以在yaml中以mybatis开头来进行配置
SpringBoot-3-数据访问&单元测试_第7张图片
采用注解来在SpringBoot中使用Mybatis:
1,首先创建DTO实例和对应的Mapper接口

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Account {

    private Long id;
    private String userId;
    private Integer money;

}


@Mapper
public interface AccountMapper {

    @Select("SELECT * FROM account WHERE id=#{id}")
    public Account getAccountById(Long id);
    
	@Insert("INSERT INTO account('id', 'userId', 'money') values(#{id}, #{userId}, #{money})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    public void insertAccount(Account account);
    
}

2,创建Service,并在Controller层调用

@Service
public class AccountService {

    @Autowired
    AccountMapper accountMapper;

    public Account getAccountById(Long id) {
        return accountMapper.getAccountById(id);
    }

}

@Controller
public class AccountController {

    @Autowired
    AccountMapper accountMapper;

    @GetMapping("/account")
    @ResponseBody
    public Account getAccountById(@RequestParam(value = "id") Long id) {
        return accountMapper.getAccountById(id);
    }
    
}

在Mybatis的基础上,还可以使用增强的Mybatis-Plus
Mybatis-Plus提供了简单的CRUD功能

1,pom中引入mybatis-plus
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
</dependency>

2,创建DTO和对应的Mapper
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Account {

    private Long id;
    private String userId;
    private Integer money;

}

@Mapper
public interface AccMapper extends BaseMapper<Account> {

}
继承的BaseMapper提供了对<T>的CRUD功能
会在DB中找到对应的名为T的表

3,创建Service接口并实现且在Controller层调用
操作account表的接口:
public interface AccService extends IService<Account> {

}

接口实现:
@Service
public class AccServiceImpl extends ServiceImpl<AccMapper, Account> implements AccService {


}Controller层调用:
@Controller
public class AccController {

    @Autowired
    AccService accService;

    @GetMapping("/acc")
    @ResponseBody
    public Account getAccountById(@RequestParam(value = "id") Long id) {
        return accService.getById(id);
    }


}

1.2 NoSQL

1.2.1 SpringBoot整合Redis

首先在pom中导入redis的starter

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

官方提供的starter的自动配置都在spring-boot-autoconfigure中
SpringBoot-3-数据访问&单元测试_第8张图片
Redis的自动配置项绑定的前缀是spring.redis,可以在yaml中自行修改配置
并准备好了连接工厂,自动导入了Lettuce客户端和Jedis客户端
且自动注入了RedisTemplate和StringRedisTemplate

在yaml中配置redis相关:
spring:
  redis:
    url: redis://coisini:123456@:r-bp1mcreqpidxx.redis.rds.aliyuncs.com:6379
    ssl: true

1.2.2 配置操作Redis

完成必要配置后,使用StringRedisTemplate操作Redis中的KV进行测试:

@SpringBootTest
public class TemplateTest {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Test
    void testRedis() {
        ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
        stringStringValueOperations.set("hello", "world");

        String val1 = stringStringValueOperations.get("hello");
    }
    
}

上述操作使用的是StringRedisTemplate,也可以采用其他客户端操作,如Jedis和Lettuce
如想要切换到Jedis,在pom中导入Jedis依赖且在yaml中声明使用Jedis客户端即可

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
无需声明版本,starter中完成了版本控制

如想要使用Lettuce客户端,只需在client-type中修改即可
同时可以修改一些特性
spring:
  redis:
    url: redis://coisini:123456@:r-bp1mcreqpidxx.redis.rds.aliyuncs.com:6379
    client-type: jedis
    jedis:
      pool:
        max-active: 10
        min-idle: 5

2 单元测试

2.1 Junit5简介

SpringBoot2.2.0开始引入Junit5作为单元测试默认库
Junit5和之前版本的Junit框架有很大不同,由三个不同子项目的几个不同模块组成
Junit5 = Junit Platform + Junit Jupiter + Junit Vintage

Junit Platform: 是在JVM上启动测试框架的基础,支持Junit自制的测试引擎,也可以接入其他引擎
JUnit Jupiter: Junit Jupiter提供Junit5新的编程模型,是JUnit5新特性的核心
				内部包含了一个测试引擎,用于在Junit Platform上运行
Junit Vintage: 为了兼容老项目,Junit vintage提供了兼容Junit4Junit3的测试引擎

新版本SpringBoot使用Junit5也非常简单,只需要在pom中导入test-starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

在测试类上使用@SpringBootTest,并在测试方法上加@Test即可
同时也可以提供@Transactional功能,结束完测试后自动回滚,保持数据一致性
SpringBoot-3-数据访问&单元测试_第9张图片

2.2 Junit5常用注解

@Test: 表示方法是测试方法

@ParameterizedTest: 表示方法是参数化测试

@RepeatedTest: 表示方法可重复执行

@DisplayName: 为测试类或测试方法设置展示名称

@BeforeEach: 表示在每个单元测试之前执行

@AfterEach: 表示在每个单元测试后执行

@BeforeAll: 表示在所有单元测试之前执行

@AfterAll: 表示在所有单元测试之后执行

@Tag: 表示单元测试类别

@Disabled: 表示测试类或测试方法不执行

@Timeout: 表示测试方法运行如果超过指定时间会报错

@ExtendWith: 为测试类或测试方法提供扩展类引用

测试@DisplayName:
SpringBoot-3-数据访问&单元测试_第10张图片
测试@BeforeEach和@AfterEach:SpringBoot-3-数据访问&单元测试_第11张图片
测试@BeforeAll和@AfterAll,使用这两个注解的方法必须是静态方法:
SpringBoot-3-数据访问&单元测试_第12张图片

2.3 断言

断言(Assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证
这些断言方法都是org.junit.jupiter.api.Assertions的静态方法
用来检查业务逻辑返回的数据是否合理,所有测试结束后,会有一个详细报告
同一个方法内前面的断言失败则后续代码不执行

简单断言方法:

assertEquals: 判断两个对象或两个原始类型是否相等

assertNotEquals: 判断两个对象或两个原始类型是否不相等

assertSame: 判断两个对象引用是否指向同一个对象

assertNotSame: 判断两个对象引用是否指向不同对象

assertTrue: 判断得到的布尔值是否为真

assertFalse: 判断得到的布尔值是否为假

assertNull: 判断给定的对象引用是否为null

assertNotNull: 判断给定的对象引用是不是null

简单断言使用: SpringBoot-3-数据访问&单元测试_第13张图片
断言机制还提供组合断言,即通过assertAll判断所有断言
通过Lambda表达式写出多条断言,全部成功则断言成功,有一个失败此断言失败:
SpringBoot-3-数据访问&单元测试_第14张图片
还有异常断言,断定业务逻辑会出现某种异常,如果出现则通过,未出现断言失败:
SpringBoot-3-数据访问&单元测试_第15张图片
还可以通过fail方法快速失败,即遇到某种条件时终止测试

@Test
    void testAssert() {
        if(cal(2, 3) != 5) {
            Assertions.fail("cal方法有误");
        }
    }

2.4 前置条件

JUnit5中的前置条件Assumptions类似断言,但不同之处在于
不满足断言会使得测试方法失败,而不满足前置条件会使得测试方法执行终止
前置条件可以看做执行测试方法的前提,当前提不满足就没必要继续执行
SpringBoot-3-数据访问&单元测试_第16张图片

2.5 参数化测试

参数化测试是JUnit5的一个新特性,它使得用不同的参数多次运行测试成为可能
利用@ValueSource等注解,指定入参,可以使用不同参数进行多次单元测试
而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码

@ValueSource: 为参数化测试指定入参来源,支持八大基础类型以及StringClass类型

@NullSource: 为参数化测试提供一个null作为入参

@EnumSource: 为参数化测试提供一个枚举的入参

@CsvFileSource: 表示读取Csv文件内容作为参数化测试入参

@MethodSource: 表示读取方法的返回值作为参数化测试入参

参数化测试使用:
SpringBoot-3-数据访问&单元测试_第17张图片
使用某个方法的返回值作为入参,提供参数的方法必须是静态的且返回Stream:
SpringBoot-3-数据访问&单元测试_第18张图片

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