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

★ 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 {@Autowiredprivate 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  {@Autowiredprivate WebApplicationContext webApplicationContext;private MockMvc mockMvc;@Beforepublic void setUp() throws Exception {mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
} 

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

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest  {private MockMvc mockMvc;@Beforepublic 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@AllArgsConstructorpublic 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 {@Autowiredprivate WebApplicationContext webApplicationContext;private MockMvc mockMvc;@Beforepublic void setUp() {mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();}@Testpublic 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 {@Autowiredprivate ProjectMapper mapper;public ProjectDO detail(String id) {return mapper.selectById(id);}}

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

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProjectServiceTest {@MockBeanprivate ProjectMapper mapper;@Autowiredprivate ProjectService service;@Testpublic 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 {@Mockprivate List list;public MockitoTest(){// 初始化 @Mock 注解MockitoAnnotations.initMocks(this);}@Testpublic 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调用真实对象apidoReturn(999).when(spy).get(999);//预设size()期望值when(spy.size()).thenReturn(100);//调用真实对象的apispy.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对象放入InOrderInOrder 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.hqwc.cn/news/164618.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode 221. 最大正方形

2023.11.8 本题使用动态规划来做。dp[i][j]数组代表:以坐标[i][j]为左下角,只包含 1 的正方形的边长最大值 。 遍历二维数组matrix,如果当前元素为0,则dp数组直接赋值0;如果当前元素为1,那么当前的边长最大…

java--实体javaBean

1.什么是实体类 1.就是一种特殊形式的类 2.这个类中的成员变量都要私有,并且要对外提供相应的getXXX,setXXX方法 3.类中必须要有一个公共的无参的构造器 2.实体类有啥应用场景 实体类只负责数据存取,而对数据的处理交给其他类来完成&…

IP地址冲突解决办法

在计算机网络中,每个设备都需要一个唯一的IP地址来与其他设备进行通信。然而,有时候会出现IP地址冲突的情况即多个设备使用了相同的IP地址。这种冲突会导致网络连接问题,因此需要及时解决。 IP地址查询:IP66_ip归属地在线查询_免费…

动手学Matplotlib画图,Matplotlib 是一个非常强大的 Python 画图工具。【Matplotlib学习笔记】

一、第一章 1.基本用法 import matplotlib.pyplot as plt import numpy as npx np.linspace(-1,1,50) y 2*x 1 plt.plot(x,y) plt.show()2.figure图像 import matplotlib.pyplot as plt import numpy as npx np.linspace(-1,1,50) y1 2*x 1 y2 x**2 plt.figure() plt…

【机器学习】Kmeans聚类算法

一、聚类简介 Clustering (聚类)是常见的unsupervised learning (无监督学习)方法,简单地说就是把相似的数据样本分到一组(簇),聚类的过程,我们并不清楚某一类是什么(通常无标签信息)&#xff0…

Windows系统C++语言环境下通过SDK进行动作捕捉数据传输

NOKOV度量动作捕捉系统可以与市面上主流的操作系统和编程语言实现通信。可以在Windows系统C语言环境下通过SDK进行动作捕捉数据传输。 一、形影软件设置 1、实时模式和后处理模式都可以通过SDK传输数据。以后处理模式为例。将模式切换到后处理模式 2、加载一个刚体数据 3、打…

Nat. Med. | 基于遗传学原发部位未知癌症的分类和治疗反应预测

今天为大家介绍的是来自Alexander Gusev团队的一篇论文。原发部位未知癌症(Cancer of unknown primary,CUP)是一种无法追溯到其原发部位的癌症,占所有癌症的3-5%。CUP缺乏已建立的靶向治疗方法,导致普遍预后…

SAPCRM销售订单集成创建

一、概述 越来越多的公司在数字化转型项目中不仅只上线SAP系统,而是将各模块外围系统同步上线,因此对于业务顾问来说,不只要写增强&报表的FS,还要提供外围系统集成的接口规范,以及集成方案,本文分享一…

【FastCAE源码阅读5】使用VTK实现鼠标拾取对象并高亮

鼠标拾取对象是很多软件的基本功能。FastCAE的拾取比较简单,是通过VTK实现的。 对几何而言,拾取类型切换在工具栏上,单击后再来单击视图区对象进行拾取,拾取后的对象会高亮显示。效果如下图: 一、拾取对象 拾取对象…

京东数据分析:2023年9月京东打印机行业品牌销售排行榜

鲸参谋监测的京东平台9月份打印机市场销售数据已出炉! 鲸参谋数据显示,今年9月,京东平台打印机的销量为60万,环比增长约32%,同比下滑约25%;销售额为5亿,环比增长约35%,同比下滑约29%…

Spark 基础知识点

Spark 基础 本文来自 B站 黑马程序员 - Spark教程 :原地址 什么是Spark 什么是Spark 1.1 定义:Apache Spark是用于大规模数据(large-scala data)处理的统一(unified)分析引擎 Spark最早源于一篇论文 Re…

MySQL第八讲·如何进行数学计算、字符串处理和条件判断?

你好,我是安然无虞。 文章目录 如何进行数学计算、字符串处理和条件判断?数学函数字符串函数条件判断函数总结 如何进行数学计算、字符串处理和条件判断? MySQL 提供了很多功能强大,而且使用起来非常方便的函数,包括…