P02项目诊断报警组件(学习操作日志记录、单元测试开发)

news2024/12/24 11:34:49

★ P02项目诊断报警组件

诊断报警组件的主要功能有:

  1. 接收、记录硬件设备上报的报警信息。
  2. 从预先设定的错误码对照表中找到对应的声光报警和蜂鸣器报警策略,结合当前的报警情况对设备下发报警指示。
  3. 将报警消息发送到消息队列,由其它组件发送给前端。
  4. 从消息队列获取用户通过前端进行的报警处理操作,更新故障报警表对应记录的处理信息,并根据预定规则调整当前的声光报警、蜂鸣器报警策略。
  5. 定期往Redis缓存写入数据,并将该数据的有效期设为写入周期的3倍。
  6. 定期从Redis缓存中获取系统监视组件写入的标志信息,如果获取失败则表示系统监视组件出现故障,产生报警记录并对设备下发报警指示。
  7. 系统监视组件产生的后端组件故障报警信息的记录和处理。
  8. 从Redis缓存获取当前系统配置参数中的各优先级报警循环时间,并在配置参数有改动时及时更新。
  9. 用户通过前端页面对历史报警信息进行查询。

职责描述:
1、学习项目。
2、单元测试

学习别人的如何操作日志记录注解

package com.wg.common.annotation;

import java.lang.annotation.*;

/**
 * 自定义操作日志记录注解
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /**
     * 模块
     */
    String title() default "";

    /**
     * 功能
     */
    String business() default "";
}

package com.wg.common.aspectj;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.wg.common.annotation.Log;
import com.wg.common.constant.Constants;
import com.wg.common.entity.OperationLog;
import com.wg.common.entity.User;
import com.wg.common.service.IOperationLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 日志aop信息
**/
@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired
    private IOperationLogService operationLogService;

    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(Log controllerLog, Object jsonResult) {
        handleLog(controllerLog, null, jsonResult);
    }

    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(Log controllerLog, Exception e)
    {
        handleLog(controllerLog, e, null);
    }

    protected void handleLog(Log controllerLog, final Exception e, Object jsonResult)
    {
        try
        {
            User user = (User) StpUtil.getSession().get("user");

            OperationLog operationLog = new OperationLog();
            operationLog.setStatus(Constants.SUCCESS);
            if (ObjectUtil.isNotNull(user))
            {
                operationLog.setUserName(user.getUserName());
                operationLog.setNickName(user.getNickName());
            }

            if (e != null)
            {
                operationLog.setStatus(Constants.FAIL);
                operationLog.setErrorMsg(StrUtil.sub(e.getMessage(), 0, 2000));
            }
            operationLog.setTitle(controllerLog.title());
            operationLog.setOperationTime(new Date());
            operationLogService.save(operationLog);
        }
        catch (Exception exp)
        {
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }
}

在这里插入图片描述

学习单元测试

首先实际完成的时候偷懒的方式就是用SquareTest生成。

Controller 测试

Spring 提供了 MockMVC 用于支持 RESTful 风格的 Spring MVC 测试,使用 MockMvcBuilder 来构造MockMvc 实例。MockMvc 有两个实现:

StandaloneMockMvcBuilder:指定 WebApplicationContext,它将会从该上下文获取相应的控制器并得到相应的 MockMvc

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest  {
    @Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;
    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
} 

DefaultMockMvcBuilder:通过参数指定一组控制器,这样就不需要从上下文获取了

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest  {
    private MockMvc mockMvc;
    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
    } 
}    

下面是一个简单的用例,对 UserController 的 /user/{id} 接口进行测试。

@RestController
@RequestMapping("user")
public class UserController {

    @GetMapping("/{id}")
    public User get(@PathVariable("id") String id) {
        return new User(1, "lst");
    }

    @Data
    @AllArgsConstructor
    public class User {
        private Integer id;
        private String name;
    }

}
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {

    @Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @Test
    public void getUser() {
        mockMvc.perform(get("/user/1")
                .accept(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
           .andExpect(content().string(containsString("\"name\":\"lst\"")));
    }
  
}
方法描述

perform:执行一个 RequestBuilder 请求,返回一个 ResultActions 实例对象,可对请求结果进行期望与其它操作

get:声明发送一个 get 请求的方法,更多的请求类型可查阅→MockMvcRequestBuilders 文档

andExpect:添加 ResultMatcher 验证规则,验证请求结果是否正确,验证规则可查阅→MockMvcResultMatchers 文档

andDo:添加 ResultHandler 结果处理器,比如调试时打印结果到控制台,更多处理器可查阅→MockMvcResultHandlers 文档

andReturn:返回执行请求的结果,该结果是一个恩 MvcResult 实例对象→MvcResult 文档

Mock 数据

在单元测试中,Service 层的调用往往涉及到对数据库、中间件等外部依赖。
如果不需要对静态方法,私有方法等特殊进行验证测试,则仅仅使用 Spring boot 自带的 Mockito 即可完成相关的测试数据 Mock。若需要则可以使用 PowerMock,简单实用,结合 Spring 可以使用注解注入。

@MockBean
SpringBoot 在执行单元测试时,会将该注解的 Bean 替换掉 IOC 容器中原生 Bean。

例如下面代码中, ProjectService 中通过 ProjectMapper 的 selectById 方法进行数据库查询操作:

@Service
public class ProjectService {

    @Autowired
    private ProjectMapper mapper;

    public ProjectDO detail(String id) {
        return mapper.selectById(id);
    }

}

此时我们可以对 Mock 一个 ProjectMapper 对象替换掉 IOC 容器中原生的 Bean,来模拟数据库查询操作,如:
复制代码

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProjectServiceTest {
  
    @MockBean
    private ProjectMapper mapper;
    @Autowired
    private ProjectService service;

    @Test
    public void detail() {
        ProjectDemoDO model = new ProjectDemoDO();
        model.setId("1");
        model.setName("dubbo-demo");
        Mockito.when(mapper.selectById("1")).thenReturn(model);
        ProjectDemoDO entity = service.detail("1");
        assertThat(entity.getName(), containsString("dubbo-demo"));
    }

}
Mockito 常用方法

mock() 对象
List list = mock(List.class);

verify() 验证互动行为

@Test
public void mockTest() {
	List list = mock(List.class);
  list.add(1);
  // 验证 add(1) 互动行为是否发生
  Mockito.verify(list).add(1);
}

when() 模拟期望结果

@Test
public void mockTest() {
  List list = mock(List.class);
  when(mock.get(0)).thenReturn("hello");
  assertThat(mock.get(0),is("hello"));
}

doThrow() 模拟抛出异常

@Test(expected = RuntimeException.class)
public void mockTest(){
  List list = mock(List.class);
  doThrow(new RuntimeException()).when(list).add(1);
  list.add(1);
}
@Mock 注解

在上面的测试中我们在每个测试方法里都 mock 了一个 List 对象,为了避免重复的 mock,使测试类更具有可读性,我们可以使用下面的注解方式来快速模拟对象:

 @RunWith(MockitoJUnitRunner.class) 
public class MockitoTest {
    @Mock
    private List list;

    public MockitoTest(){
      	// 初始化 @Mock 注解
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void shorthand(){
        list.add(1);
        verify(list).add(1);
    }
}

when() 参数匹配

@Test
public void mockTest(){
	Comparable comparable = mock(Comparable.class);
  //预设根据不同的参数返回不同的结果
  when(comparable.compareTo("Test")).thenReturn(1);
  when(comparable.compareTo("Omg")).thenReturn(2);
  assertThat(comparable.compareTo("Test"),is(1));
  assertThat(comparable.compareTo("Omg"),is(2));
  //对于没有预设的情况会返回默认值
   assertThat(list.get(1),is(999));
   assertThat(comparable.compareTo("Not stub"),is(0));
}
spy() 监控真实对象

Mock 不是真实的对象,它只是创建了一个虚拟对象,并可以设置对象行为。而 Spy是一个真实的对象,但它可以设置对象行为。

@Test(expected = IndexOutOfBoundsException.class)
public void mockTest(){
  List list = new LinkedList();
  List spy = spy(list);
  //下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常
  when(spy.get(0)).thenReturn(3);
  //使用doReturn-when可以避免when-thenReturn调用真实对象api
  doReturn(999).when(spy).get(999);
  //预设size()期望值
  when(spy.size()).thenReturn(100);
  //调用真实对象的api
  spy.add(1);
  spy.add(2);
  assertThat(spy.size(),is(100));
  assertThat(spy.size(),is(1));
  assertThat(spy.size(),is(2));
  verify(spy).add(1);
  verify(spy).add(2);
  assertThat(spy.get(999),is(999));
}

reset() 重置 mock

@Test
public void reset_mock(){
  List list = mock(List.class);
  when(list.size()).thenReturn(10);
  list.add(1);
	assertThat(list.size(),is(10));
  //重置mock,清除所有的互动和预设
  reset(list);
  assertThat(list.size(),is(0));
}

times() 验证调用次数

@Test
public void verifying_number_of_invocations(){
  List list = mock(List.class);
  list.add(1);
  list.add(2);
  list.add(2);
  list.add(3);
  list.add(3);
  list.add(3);
  //验证是否被调用一次,等效于下面的times(1)
  verify(list).add(1);
  verify(list,times(1)).add(1);
  //验证是否被调用2次
  verify(list,times(2)).add(2);
  //验证是否被调用3次
  verify(list,times(3)).add(3);
  //验证是否从未被调用过
  verify(list,never()).add(4);
  //验证至少调用一次
  verify(list,atLeastOnce()).add(1);
  //验证至少调用2次
  verify(list,atLeast(2)).add(2);
  //验证至多调用3次
  verify(list,atMost(3)).add(3);
}

inOrder() 验证执行顺序

@Test
public void verification_in_order(){
  List list = mock(List.class);
  List list2 = mock(List.class);
  list.add(1);
  list2.add("hello");
  list.add(2);
  list2.add("world");
  //将需要排序的mock对象放入InOrder
  InOrder inOrder = inOrder(list,list2);
  //下面的代码不能颠倒顺序,验证执行顺序
  inOrder.verify(list).add(1);
  inOrder.verify(list2).add("hello");
  inOrder.verify(list).add(2);
  inOrder.verify(list2).add("world");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1185121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux常用命令及项目部署

目录 Linux介绍 Linux环境 下载xshell 常见的Linux命令 搭建Java部署环境 1.jdk 2.tomcat 3.mysql 进行部署 Linux介绍 Linux操作系统是和Windows并列的关系,Linux主要通过命令行进行操作的。 Linux环境 1.使用虚拟机,电脑上安装虚拟机软件 …

快来看看如何拿下7+干湿结合生信思路。赶紧拿起笔记本

今天给同学们分享一篇生信文章“CENPF/CDK1 signaling pathway enhances the progression of adrenocortical carcinoma by regulating the G2/M-phase cell cycle”,这篇文章发表在J Transl Med期刊上,影响因子为7.4。 结果解读: CENPF在AC…

Python实现图片与PDF互相转换

目录 图片转PDF文件夹所有图片转为1个PDF文件夹指定图片转为1个PDF文件夹所有图片分别转为PDF举例 PDF转图片指定PDF转为图片文件夹所有PDF转为图片举例 图片转PDF 之前的一篇博客《Python合并拼接图片》,可对图片进行合并拼接 使用前需要安装PyMuPDF库&#xff0c…

lua脚本实现redis分布式锁(脚本解析)

文章目录 lua介绍lua基本语法redis执行lua脚本 - EVAL指令使用lua保证删除原子性 lua介绍 Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 设…

最适合后端程序员要学的前端基本知识js版本

本文章适合有后端基础,也对前端知识有所了解的同学,简单而精准的了解后端程序员要了解的前端知识。让自己能看懂前端js,html和css版本后续写出。。。。 自定义对象 在对象中创建对象的行为时若是要调用对象属性,要加this 列如&a…

kubernetes 认证授权

目录 一、kubernetes API访问控制 二、pod绑定sa 三、认证 四、授权 一、kubernetes API访问控制 Authentication(认证)认证方式现共有8种,可以启用一种或多种认证方式,只要有一种认证方式通过,就不再进行其它方式…

【Axure高保真原型】树切换动态面板案例

今天和大家分享树切换动态面板的原型模板,点击树的箭头可以打开或者收起子节点,点击最后一级人物节点,可以切换右侧面板的状态到对应的页面,左侧的树是通过中继器制作的,使用简单,只需要按要求填写中继器表…

人大金仓三大兼容:SQL Server迁移无忧

SQL Server在数据库领域一直占据着重要地位。作为一款成熟稳定的关系型数据库管理系统,SQL Server在国内有着广泛的用户群体,医疗、海关、政务等行业的核心业务系统多采用SQL Server数据库。随着政策与市场的双重驱动,信息技术应用创新产业的…

【快速使用ShardingJDBC的哈希分片策略进行分表】

文章目录 🔊博主介绍🥤本文内容🍊1.引入maven依赖🍊2.启动类上添加注解MapperScan🍊3.添加application.properties配置🍊4.普通的自定义实体类🍊5.写个测试类验证一下🍊6.控制台打印…

竞赛 目标检测-行人车辆检测流量计数

文章目录 前言1\. 目标检测概况1.1 什么是目标检测?1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 前言 🔥 优质竞赛项目系列,今天要分享的是 行人车辆目标检测计数系统 …

Linux之make/maakefile

access不是实时更新的。 printf打印并不是直接给屏幕而是先放到缓冲区。 可以通过fflush(stdout)强制刷新缓冲区。 换行是指直接到同一位置的下一行,回车是回到开头。

【MySQL数据库】 七

本文主要介绍了Java的JDBC编程的过程. 超详细 !!! 一.JDBC JDBC就是通过Java代码,来操作数据库 由于我们在实际开发中,绝大部分都是用代码来操作数据库的 , 因此一个成熟的数据库,都会提供一些API让程序员来使用. 常见的数据库比如mysql / oracl / sqlserver / SQLite 都会提…

Python类与对象:类的定义、实例化、方法、属性、构造函数

文章目录 类的定义类的实例化方法属性构造函数Python 类和对象是面向对象编程的基础。在 Python 中,几乎所有东西都是对象,拥有属性和方法。类是创建对象的蓝图或模板。让我们一步步来探索类的定义、实例化、方法、属性以及构造函数,并提供详细的代码示例。 类的定义 在 P…

SQL注入漏洞 其他注入

文章目录 宽字节注入案例 HTTP头部注入Cookie注入base64User-Agent注入Referer 注入 SQL注入读写文件条件1.是否拥有读写权限2.文件路径3.secure_file_priv 读取文件写入文件 SQLMap安装sqlmapkail 源安装仓库克隆 参数简介快速入门;SQLmap(常规&#xf…

【Docker】设置容器系统字符集zh_CN.UTF-8退出失效:关于Docker容器配置环境变量,再次进入失效问题

设置容器系统字符集zh_CN.UTF-8退出失效:关于Docker容器配置环境变量,再次进入失效问题 修改正在运行的Docker容器内的字符集: 先进入Docker容器:docker exec -it 容器ID /bin/bash查看是否支持中文字符集:locale -a | grep zh&a…

B站双11,联手天猫暴涨2亿消费新势力

一直以来,手持高活跃、高粘性用户群体的B站是行业用来观察年轻人消费习惯的重要平台。以至于用户群体的不断壮大带动了B站的商业价值。如今B站的商业舞台越来越大,不断地向外界招手,欢迎更多品牌积极加入到这个千万年轻人聚集的内容社区。 2…

如何有效防爬虫?教你打造安全堡垒

企业拥抱数字化技术的过程中,网络犯罪分子的“战术”也更难以觉察,并且这些攻击越来越自动化和复杂,也更加难以觉察。在众多攻击手段总,网络爬虫是企业面临的主要安全挑战,对于企业所造成的经济损失是难以计量的。那么…

设备密集型单位如何提升效率?智能巡检软件哪个好?

在设备密集型单位,如钢铁、化工、电力、烟草、日用品等行业以及运维商,日常工作中面临着设备巡检这一重要且繁琐的任务。传统的巡检方式往往依靠纸质记录,数据难以进行统计或分析,巡检人员需要手动记录各种数据,不仅效…

visual studio 启用DPI识别功能

在开发widow程序时,有时必须将电脑 设置-->显示-->缩放与布局-->更改文本、应用项目的大小-->100%后,程序的画面才能正确运行,居说这是锁定了dpi的原因,需要启dpi识别功能。设置方法如下: 或者

unity - Blend Shape - 变形器 - 实践

文章目录 目的Blend Shape 逐顶点 多个混合思路Blender3Ds maxUnity 中使用Project 目的 拾遗,备份 Blend Shape 逐顶点 多个混合思路 blend shape 基于: vertex number, vertex sn 相同,才能正常混合、播放 也就是 vertex buffer 的顶点数…