springboot2单元测试和指标监控(代码片段)

晓未苏 晓未苏     2022-11-03     799

关键词:

单元测试

1、JUnit5 的变化

Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
作为最新版本的JUnit框架,JUnit5与之前版本的Junit框架有很大的不同。由三个不同子项目的几个不同模块组成。

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit Platform: Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。
JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部 包含了一个测试引擎,用于在Junit Platform上运行。
JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。


注意:
SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入(不能使用junit4的功能 @Test)
JUnit 5’s Vintage Engine Removed from spring-boot-starter-test,如果需要继续兼容junit4需要自行引入vintage

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

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

现在版本:

@SpringBootTest
class Boot05WebAdminApplicationTests 


    @Test
    void contextLoads() 

    


以前:
@SpringBootTest + @RunWith(SpringTest.class)
SpringBoot整合Junit以后。

  • 编写测试方法:@Test标注(注意需要使用junit5版本的注解)
  • Junit类具有Spring的功能,@Autowired、比如 @Transactional 标注测试方法,测试完成后自动回滚

2、JUnit5常用注解

JUnit5的注解与JUnit4的注解有所变化
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
**@Test 😗*表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
@ParameterizedTest :表示方法是参数化测试,下方会有详细介绍
@RepeatedTest :表示方法可重复执行,下方会有详细介绍
@DisplayName :为测试类或者测试方法设置展示名称
@BeforeEach :表示在每个单元测试之前执行
@AfterEach :表示在每个单元测试之后执行
@BeforeAll :表示在所有单元测试之前执行
@AfterAll :表示在所有单元测试之后执行
@Tag :表示单元测试类别,类似于JUnit4中的@Categories
@Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Timeout :表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith :为测试类或测试方法提供扩展类引用

import org.junit.jupiter.api.Test; //注意这里使用的是jupiter的Test注解!!


public class TestDemo 

  @Test
  @DisplayName("第一次测试")
  public void firstTest() 
      System.out.println("hello world");
  

3、断言(assertions)

断言(assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证。这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法。JUnit 5 内置的断言可以分成如下几个类别:
检查业务逻辑返回的数据是否合理。
所有的测试运行结束以后,会有一个详细的测试报告;

1、简单断言

用来对单个值进行简单的验证。如:

方法说明
assertEquals判断两个对象或两个原始类型是否相等
assertNotEquals判断两个对象或两个原始类型是否不相等
assertSame判断两个对象引用是否指向同一个对象
assertNotSame判断两个对象引用是否指向不同的对象
assertTrue判断给定的布尔值是否为 true
assertTrue判断两个对象或两个原始类型是否相等
assertFalse判断给定的布尔值是否为 false
assertNull判断给定的对象引用是否为 null
assertNotNull判断给定的对象引用是否不为 null
@Test
@DisplayName("simple assertion")
public void simple() 
     assertEquals(3, 1 + 2, "simple math");
     assertNotEquals(3, 1 + 1);

     assertNotSame(new Object(), new Object());
     Object obj = new Object();
     assertSame(obj, obj);

     assertFalse(1 > 2);
     assertTrue(1 < 2);

     assertNull(null);
     assertNotNull(new Object());

2、数组断言

通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等

@Test
@DisplayName("array assertion")
public void array() 
 assertArrayEquals(new int[]1, 2, new int[] 1, 2);

3、组合断言

assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言

@Test
@DisplayName("assert all")
public void all() 
 assertAll("Math",
    () -> assertEquals(2, 1 + 1),
    () -> assertTrue(1 > 0)
 );

4、异常断言

在JUnit4时期,想要测试方法的异常情况时,需要用@Rule注解的ExpectedException变量还是比较麻烦的。而JUnit5提供了一种新的断言方式Assertions.assertThrows() ,配合函数式编程就可以进行使用。

@Test
@DisplayName("异常测试")
public void exceptionTest() 
    ArithmeticException exception = Assertions.assertThrows(
           //扔出断言异常
            ArithmeticException.class, () -> System.out.println(1 % 0));


5、超时断言

Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间

@Test
@DisplayName("超时测试")
public void timeoutTest() 
    //如果测试方法时间超过1s将会异常
    Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));

6、快速失败

@Test
@DisplayName("fail")
public void shouldFail() 
 fail("This should fail");

4、前置条件(assumptions)

Unit 5 中的前置条件(assumptions【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。

@DisplayName("前置条件")
public class AssumptionsTest 
 private final String environment = "DEV";
 
 @Test
 @DisplayName("simple")
 public void simpleAssume() 
    assumeTrue(Objects.equals(this.environment, "DEV"));
    assumeFalse(() -> Objects.equals(this.environment, "PROD"));
 
 
 @Test
 @DisplayName("assume then do")
 public void assumeThenDo() 
    assumingThat(
       Objects.equals(this.environment, "DEV"),
       () -> System.out.println("In DEV")
    );
 

assumeTrue 和 assumFalse 确保给定的条件为 true 或 false,不满足条件会使得测试执行终止。assumingThat 的参数是表示条件的布尔值和对应的 Executable 接口的实现对象。只有条件满足时,Executable 对象才会被执行;当条件不满足时,测试执行并不会终止。

5、嵌套测试

JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。

@DisplayName("A stack")
class TestingAStackDemo 

    Stack<Object> stack;

    @Test
    @DisplayName("is instantiated with new Stack()")
    void isInstantiatedWithNew() 
        new Stack<>();
    

    @Nested
    @DisplayName("when new")
    class WhenNew 

        @BeforeEach
        void createNewStack() 
            stack = new Stack<>();
        

        @Test
        @DisplayName("is empty")
        void isEmpty() 
            assertTrue(stack.isEmpty());
        

        @Test
        @DisplayName("throws EmptyStackException when popped")
        void throwsExceptionWhenPopped() 
            assertThrows(EmptyStackException.class, stack::pop);
        

        @Test
        @DisplayName("throws EmptyStackException when peeked")
        void throwsExceptionWhenPeeked() 
            assertThrows(EmptyStackException.class, stack::peek);
        

        @Nested
        @DisplayName("after pushing an element")
        class AfterPushing 

            String anElement = "an element";

            @BeforeEach
            void pushAnElement() 
                stack.push(anElement);
            

            @Test
            @DisplayName("it is no longer empty")
            void isNotEmpty() 
                assertFalse(stack.isEmpty());
            

            @Test
            @DisplayName("returns the element when popped and is empty")
            void returnElementWhenPopped() 
                assertEquals(anElement, stack.pop());
                assertTrue(stack.isEmpty());
            

            @Test
            @DisplayName("returns the element when peeked but remains not empty")
            void returnElementWhenPeeked() 
                assertEquals(anElement, stack.peek());
                assertFalse(stack.isEmpty());
            
        
    

6、参数化测试

参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。

利用**@ValueSource**等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。

@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)

当然如果参数化测试仅仅只能做到指定普通的入参还达不到让我觉得惊艳的地步。让我真正感到他的强大之处的地方在于他可以支持外部的各类入参。如:CSV,YML,JSON 文件甚至方法的返回值也可以作为入参。只需要去实现ArgumentsProvider接口,任何外部文件都可以作为它的入参。

@ParameterizedTest
@ValueSource(strings = "one", "two", "three")
@DisplayName("参数化测试1")
public void parameterizedTest1(String string) 
    System.out.println(string);
    Assertions.assertTrue(StringUtils.isNotBlank(string));



@ParameterizedTest
@MethodSource("method")    //指定方法名
@DisplayName("方法来源参数")
public void testWithExplicitLocalMethodSource(String name) 
    System.out.println(name);
    Assertions.assertNotNull(name);


static Stream<String> method() 
    return Stream.of("apple", "banana");

7、Junit4迁移Junit5指南

在进行迁移的时候需要注意如下的变化:

  • 注解在 org.junit.jupiter.api 包中,断言在 org.junit.jupiter.api.Assertions 类中,前置条件在 org.junit.jupiter.api.Assumptions 类中。
  • 把@Before 和@After 替换成@BeforeEach 和@AfterEach。
  • 把@BeforeClass 和@AfterClass 替换成@BeforeAll 和@AfterAll。
  • 把@Ignore 替换成@Disabled。
  • 把@Category 替换成@Tag。
  • 把@RunWith、@Rule 和@ClassRule 替换成@ExtendWith。

指标监控

1、SpringBoot Actuator

1、简介

未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。

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

2、1.x与2.x的不同

3、如何使用

management:
  endpoints:
    enabled-by-default: true #暴露所有端点信息
    web:
      exposure:
        include: '*'  #以web方式暴露

4、可视化

https://github.com/codecentric/spring-boot-admin

2、Actuator Endpoint

1、最常使用的端点



如果您的应用程序是Web应用程序(Spring MVC,Spring WebFlux或Jersey),则可以使用以下附加端点:

最常用的Endpoint

  • Health:监控状况
  • Metrics:运行时指标
  • Loggers:日志记录

2、Health Endpoint

健康检查端点,我们一般用于在云平台,平台会定时的检查应用的健康状况,我们就需要Health Endpoint可以为平台返回当前应用的一系列组件健康状况的集合。

重要的几点:

  • health endpoint返回的结果,应该是一系列健康检查后的一个汇总报告
  • 很多的健康检查默认已经自动配置好了,比如:数据库、redis等
  • 可以很容易的添加自定义的健康检查机制

3、Metrics Endpoint

提供详细的、层级的、空间指标信息,这些信息可以被pull(主动推送)或者push(被动获取)方式得到;

  • 通过Metrics对接多种监控系统
  • 简化核心Metrics开发
  • 添加自定义Metrics或者扩展已有Metrics

4、管理Endpoints

1、开启与禁用Endpoints

  • 默认所有的Endpoint除过shutdown都是开启的。
  • 需要开启或者禁用某个Endpoint。配置模式为 management.endpoint.<endpointName>.enabled = true
management:
  endpoint:
    beans:
      enabled: true
  • 或者禁用所有的Endpoint然后手动开启指定的Endpoint
management:
  endpoints:
    enabled-by-default: false
  endpoint:
    beans:
      enabled: true
    health:
      enabled: true

2、暴露Endpoints

支持的暴露方式

  • HTTP:默认只暴露health和info Endpoint
  • JMX:默认暴露所有Endpoint
  • 除过health和info,剩下的Endpoint都应该进行保护访问。如果引入SpringSecurity,则会默认配置安全访问规则


3、定制 Endpoint

1、定制 Health 信息

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class MyHealthIndicator implements HealthIndicator 

    @Override
    public Health health() 
        int errorCode = check(); // perform some specific health check
        if (errorCode != 0) 
            return Health.down().withDetail("Error Code", errorCode).build();
        
        return Health.up().build();
    



构建Health
Health build = Health.down()
                .withDetail("msg", "error service")
                .withDetail("code", "500")
                .withException(new RuntimeException())
                .build();
management:
    health:
      enabled: true
      show-details: always #总是显示详细信息。可显示每个模块的状态信息
@Component
public class MyComHealthIndicator extends AbstractHealthIndicator 

    /**
     * 真实的检查方法
     * @param builder
     * @throws Exception
     */
    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception 
        //mongodb。  获取连接进行测试
        Map<String,Object> map = new HashMap<>();
        // 检查完成
        if(1 == 2)
//            builder.up(); //健康
            builder.status(Status.UP);
            map.put("count",1);
            map.put("ms",100);
        else 
//            builder.down();
            builder.status(Status.OUT_OF_SERVICE);
            map.put("err","连接超时");
            map.put("ms",3000);
        


        builder.withDetail("code",100)
                .withDetails(map);

    

2、定制info信息

常用两种方式

1、编写配置文件

info:
  appName: boot-admin
  version: 2.0.1
  mavenProjectName: @project.artifactId@  #使用@@可以获取maven的pom文件值
  mavenProjectVersion: @project.version@

2、编写InfoContributor

import java.util.Collections;

import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;

@Component
public class ExampleInfoContributor implements InfoContributor 

    @Override
    public void springboot2---指标监控(代码片段)

指标监控1、SpringBootActuator1、简介2、1.x与2.x的不同3、如何使用2、ActuatorEndpoint1、最常使用的端点最常用的Endpoint2、HealthEndpoint3、MetricsEndpoint4、管理Endpoints1、开启与禁用Endpoints2、暴露Endpoints(监控端点)定制Endpoint1、定制一个组件... 查看详情

springboot2核心功能---指标监控(代码片段)

一、SpringBootActuator1.1、简介未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。&l... 查看详情

springboot2——指标监控actuator多环境切换profile和自定义starter(代码片段)

SpringBoot2——指标监控actuator、多环境切换Profile和自定义starter一、SpringBootActuator1.1SpringBootActuator的使用1.2Endpoints1.2.1端点暴露配置1.2.2重要端点解析二、多环境切换Profile2.1多配置文件2.2yaml的多文档块2.3配置文件的加载顺序三、自... 查看详情

springboot2_单元测试(代码片段)

07、单元测试1、JUnit5的变化SpringBoot2.2.0版本开始引入JUnit5作为单元测试默认库作为最新版本的JUnit框架,JUnit5与之前版本的Junit框架有很大的不同。由三个不同子项目的几个不同模块组成。JUnit5=JUnitPlatform+JUnitJupiter+JU... 查看详情

springboot2---单元测试(junit5)(代码片段)

...套测试6、参数化测试Junit4到Junit5的迁移指南JUnit5的变化SpringBoot2.2.0版本开始引入JUnit5作为单元测试默认库注意࿱ 查看详情

springboot2——数据访问的集成&单元测试(junit5)(代码片段)

SpringBoot2——数据访问的集成&单元测试(JUnit5)一、数据访问1.1数据库场景的自动配置(HikariDataSource)1.2整合druid数据源1.2.1自定义druid数据源1.2.2使用官方starter方式1.3整合MyBatis操作(重点)1.3.1整合过... 查看详情

4go语言单元测试性能测试与监控(代码片段)

4、Go语言单元测试、性能测试与监控1、单元测试1.1单元测试简介1.2testing的使用1.3案例1.4测试中一些函数的区别2、代码覆盖率3、断言库4、BDD测试框架5、基准测试5.1基准测试简介5.2基准测试案例6、性能监控7、常见的调优参数1、... 查看详情

4go语言单元测试性能测试与监控(代码片段)

4、Go语言单元测试、性能测试与监控1、单元测试1.1单元测试简介1.2testing的使用1.3案例1.4测试中一些函数的区别2、代码覆盖率3、断言库4、BDD测试框架5、基准测试5.1基准测试简介5.2基准测试案例6、性能监控7、常见的调优参数1、... 查看详情

springboot2核心功能---单元测试(代码片段)

一、JUnit5的变化SpringBoot2.2.0版本开始引入JUnit5作为单元测试默认库作为最新版本的JUnit框架,JUnit5与之前版本的Junit框架有很大的不同。由三个不同子项目的几个不同模块组成。JUnit5=JUnitPlatform+JUnitJupiter+JUnitVintageJUnit... 查看详情

springboot2.x实践记:@springboottest(代码片段)

目录@SpringBootTest用@SpringBootTest集成测试用@SpringBootTest单元测试小结TL;DR在SpringBoot中做测试,默认使用@SpringBootTest注解,今天我们就来快速学习如何进行单元测试或集成测试。1.@SpringBootTest运行SprngBoot测试... 查看详情

springboot2.x实践记:@springboottest(代码片段)

目录@SpringBootTest用@SpringBootTest集成测试用@SpringBootTest单元测试小结TL;DR在SpringBoot中做测试,默认使用@SpringBootTest注解,今天我们就来快速学习如何进行单元测试或集成测试。1.@SpringBootTest运行SprngBoot测试... 查看详情

eclipse搭建springboot项目单元测试(代码片段)

知识点:Springboot2.0单元测试和自定义异常处理  1、@SpringBootTest单元测试     1)、引入相关依赖<!--springboot程序测试依赖,如果是自动创建项目默认添加--><dependency><groupId>org.springframework.boot</groupId><art... 查看详情

系统设计指标监控和告警系统(代码片段)

在本文中,我们将探讨如何设计一个可扩展的指标监控和告警系统。一个好的监控和告警系统,对基础设施的可观察性,高可用性,可靠性方面发挥着关键作用。下图显示了市面上一些流行的指标监控和告警服务... 查看详情

性能测试之redis和nginx性能监控(代码片段)

...另外一种是图形化页面查看。但是实际上,我们性能测试主要更多的是关注性能测试指标本身。首先,我们来查看一下命令行模式。----infoinfo命令展 查看详情

springboot2----数据访问(代码片段)

数据访问数据源的自动配置---默认是HikariDataSource导入JDBC场景分析自动配置自动配置的类修改配置项使用Druid数据源druid官方github地址自定义方式创建数据源Driud内置监控页面功能开启Driud监控统计功能开启(sql监控)web-jdbc关联的监... 查看详情

8.kong入门与实战基于nginx和openresty的云原生微服务网关---指标监控与报警(代码片段)

第 8章指标监控与报警  常见的监控指标有,cpu使用率,内使用率,GC,磁盘IO,网络流量,网络延迟,请求速度,请求排队,链接数,用户态与内核态的上下文切换等。 指标监控和报警主要分为以下6个方面: 1.采集指标数据... 查看详情

8.携程架构实践---监控(代码片段)

第8章监控8.1指标监控和告警系统Hickwall Hickwall是xc在Metrics方面的主要监控系统,可以提供指标数据的采集,存储,展示和告警。 8.1.1指标监控的应用和挑战 指标监控系统是一个对时序指标进行采集... 查看详情

使用githubactions和codecov监控c/c++仓库的代码覆盖率(代码片段)

...盖率是衡量代码质量的指标之一,它意味着你编写的单元测试、回归测试是否有完整执行到所有代码行。对于C/C++这种需要“小心翼翼”的编程语言,内存泄漏、越界、野指针等问 查看详情