如何编写测试用例
代码质量管理是软件开发过程中的关键组成部分,比如我们常说的代码规范、代码可读性、单元测试和测试覆盖率等,对于研发人员来说单元测试和测试覆盖率是保障自己所编写代码的质量的重要手段;好的用例可以帮助研发人员确保代码质量和稳定性、减少维护成本、提高开发效率以及促进团队合作。之前看过一篇关于 OceanBase 质量之道的文章,文章中提到的工程理念就把测试作为非常重要的组成部分,是和研发同样重要的组成部分;也听过内部的同学说过,OB 最核心的是用例。
OceanBase工程理念:经过多年的摸索,OceanBase团队打造了独特的工程文化。测试和开发同时进行,功能测试不再是一个独立分开的过程,而是融入到开发环节,从源端控制引入bug的概率。资深测试人员的精力主要放在难度较大的bug的发现,测试体系建设和相关技术钻研、测试自动化实施。我们建立了一套高效的代码准入流程,防范了许多初级的问题,提升了团队整体的研发效率。
由此可见,测试用例对于项目的重要性。从实际的工作中,也会发现大多数的同学对于如何编写测试用例其实是比较模糊的,在以项目交付为核心思路的工程实践中,测试用例往往只占整个工程周期相当小的一部分,更多时候是依赖测试团队进行功能测试,属于纯黑盒测试。那么这种测试对于业务常规流程可以起到一定的作用,但是对于一些边界问题其实很难 cover 住;另外,基于黑盒模式的功能性测试对于研发团队本身来说,除了拿到准入的测试报告之外,并无其他帮助,当研发需要对代码进行重构或者升级某部分组件时,没有用例的保障,则会将风险直接带到线上环境去。
常见的测试方式
在既往的工作团队中,关于测试方式,包括我自己在内,在没系统了解过测试理论之前,对于各种测试方式也是模棱两可;因为测试方式的种类实在是多又杂。下面是梳理的常见的测试方式,按照不同的维度进行了分类。
分类维度 | 测试方式 | 说明 |
---|---|---|
测试目标 | 功能测试 | 验证系统是否按照规格说明的功能需求进行操作和响应。 |
性能测试 | 评估系统在不同负载条件下的性能表现。 | |
安全性测试 | 发现系统的安全漏洞和弱点,以确保系统不容易受到攻击。 | |
回归测试 | 确保在对系统进行修改后,没有引入新的错误或破坏已有功能。 | |
可用性测试 | 评估系统的用户界面和用户体验。 | |
兼容性测试 | 验证系统在不同浏览器、操作系统和设备上的兼容性。 | |
测试层次 | 单元测试 | 验证单个代码单元(通常是函数、方法、类等)的正确性。 |
组件测试 | 验证单个软件组件的功能性和正确性。 | |
集成测试 | 验证不同组件、模块或服务之间的接口和协同工作。 | |
系统测试 | 验证整个系统是否按照需求规格正常运行。 | |
验收测试 | 由最终用户或客户进行的测试,以验证系统是否满足其需求和期望。 | |
测试方法 | 手动测试 | 测试人员手动执行测试用例,模拟用户的操作。 |
自动化测试 | 使用自动化测试工具和脚本来执行测试用例,提高测试效率和一致性。 | |
白盒测试 | 关注内部代码逻辑,通常由开发人员执行。 | |
黑盒测试 | 关注输入和输出,不关心内部代码逻辑。 | |
灰盒测试 | 结合了白盒测试和黑盒测试的特点。 | |
执行时机 | 静态测试 | 在代码编写之前或编译之后执行,包括静态代码分析、代码审查等。 |
动态测试 | 在运行时执行,包括各种类型的功能测试、性能测试等。 | |
测试对象 | 功能测试 | 测试系统的功能性。 |
非功能测试 | 测试系统的非功能性特征,如性能、安全性、可用性等。 | |
白盒测试 | 测试代码的内部逻辑和结构。 | |
黑盒测试 | 测试系统的输入和输出,不考虑内部实现。 |
每种测试方式都有其独特的目标和方法,可以在软件开发生命周期的不同阶段进行。不同的测试方式在不同的测试维度分类下会有一些重叠,这是正常的,但是他们的关注点是一致的。
在本篇文章中,主要更偏向于研发侧,所以从测试层次角度来看,更多的是关注单元测试(UT)、组件测试(CT)以及集成测试(IT)。总体来说,UT 关注代码单元的正确性,CT关注组件的功能性,IT关注不同组件的集成和协同工作。这些测试层次通常是渐进的,从UT开始,然后是CT,最后是IT。不同的测试方式在软件测试策略中起着不同的作用,这些测试手段的目的就是共同确保软件在各个层次上的质量和稳定性。
下面会通过一些具体的例子来阐述不同的测试方式,主要是针对单元测试、组件测试和集成测试;项目基于 Spingboot 2.4.12 版本,使用 Junit4 和 Mockito 两种测试工具包。
UT、CT 和 IT
在具体看案例之前,先把几个测试工具跑出来,做个简单了解。
测试工具
下面的案例中主要涉及到的测试工具和框架包括:spring-boot-starter-test
、junit4
和Mockito
。
spring-boot-starter-test
官方文档:docs.spring.io/spring-boot…
spring-boot-starter-test
是 Spring Boot 提供的一个用于测试的依赖库,它简化了 Spring Boot 应用程序的测试过程,提供了许多有用的工具和类,帮助开发人员编写高效、可靠的单元测试和集成测试。就目前而言,JAVA 技术栈的项目是绕不开 Spring 这套体系的,而绝大多数情况下,在 spring 或者 springBoot 项目中,我们需要依赖 spring 容器刷新之后去测试相应的逻辑,spring-boot-starter-test
就是做这个事情的。
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
junit4
JUnit 4 是一个用于 Java 编程语言的单元测试框架。目前版本是 JUnit 5,目前我们项目中使用的是 JUnit4。以下是 JUnit 4 中一些常用的特性和概念:
- 注解驱动的测试:JUnit 4使用注解来标记测试方法,以指定哪些方法应该被运行为测试。常见的测试注解包括 @Test 用于标记测试方法、@Before 用于标记在每个测试方法之前运行的方法、@After 用于标记在每个测试方法之后运行的方法等。对于全局资源的初始化和释放可以通过 @BeforeClass 和 @AfterClass 来搞定。
- 测试套件:JUnit 4允许你将多个测试类组合在一起,形成一个测试套件,然后可以一次运行所有测试类。这对于组织和管理测试非常有用。
- 断言:JUnit 4提供了一系列的断言方法,用于验证测试中的条件是否为真。如果条件不满足,断言将引发测试失败。常见的断言方法包括 assertEquals、assertTrue、assertFalse、assertNull、assertNotNull 等。
- 运行器(Runners) :JUnit 4引入了运行器的概念,允许你扩展测试的执行方式。JUnit 4提供了一些内置的运行器,例如 BlockJUnit4ClassRunner 用于普通的 JUnit 测试类,还有一些用于特定用途的运行器,如 Parameterized 用于参数化测试。目前在 springboot 中,使用了 SpringRunner 其实也是 BlockJUnit4ClassRunner 的子类。
Mockito
Mockito 是一个用于模拟对象的框架,用于创建和配置模拟对象,以模拟外部依赖。Mockito 的主要焦点是模拟外部依赖,以便在单元测试中隔离被测试的代码,并确保它与外部依赖正确交互。和 JUnit 4 的区别在于,JUnit 4 是一个单元测试框架,用于编写和运行测试用例,JUnit 4 的主要焦点是定义和执行测试,以及管理测试生命周期。
单元测试(UT)
在前面的测试分类中,单元测试主要是验证单个代码单元(通常是函数、方法、类等)的正确性;在实际的项目中,单元测试主要是对于一个封装好的工具类的测试。如在 DateUtil 工具类中有一个方法:
-
public static String getDate(Date date, String pattern) {
-
if (null == date) {
-
return null;
-
}
-
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
-
return sdf.format(date);
-
}
右击选中方法,goto -> test,也可以通过相应的快捷键直接创建当前选中方法的测试用例。
相应的测试代码如下:
-
public class DateUtilTest {
-
@Test
-
public void test_getDate() {
-
int dateYear = DateUtil.getDateYear(new Date());
-
String yyyy = DateUtil.getDate(new Date(), "YYYY");
-
Assert.assertEquals(String.valueOf(dateYear), yyyy);
-
}
-
}
这里覆盖了正常的情况,对于传入 date 为 null 的分支并未覆盖到;所以对于强调覆盖率必须满足一定阈值的情况(之前的一个项目中,在 CI 流程中会对当前提供的代码覆盖率进行严格把控,比如行覆盖率比如达到 75% 才能被 merge),则对于不同分支逻辑也需要提供对应的用例。
-
// 当date 为 null 时,期望返回 null
-
@Test
-
public void test_getDate_when_date_null_thenReturn_null() {
-
String result = DateUtil.getDate(null, "YYYY");
-
Assert.assertEquals(null, result);
-
}
组件测试(CT)/集成测试(IT)
我们目前基于 SpringBoot test 的测试,大体可以归类于组件测试;这种情况只需要针对当前服务自己的组件进行设计用例;对于可能涉及到的上下游依赖,一般可以通过 mock 的方式来绕过,从而使得当前应用的用例 focus 在自己的业务逻辑上。
使用 mock 代替实际请求
场景描述:UserCaseService 中有个 getUserCaseList 方法,通过传入一个 UserCaseRequest 参数,然后去另一个服务拉取当前用户的事件列表
;代码如下:
-
public Response<CaseResponse> getUserCaseList(UserCaseRequest request) {
-
Map<String, Object> param = new HashMap<>();
-
param.put("phone",request.getPhone());
-
param.put("pageNo",request.getPageNo());
-
param.put("pageSize",request.getPageSize());
-
JSONObject result = HttpUtils.useHHMApi("/miniapp/user/case", param);
-
Response<CaseResponse> response = result.toJavaObject(result, Response.class);
-
return response;
-
}
在 HttpUtils 中,底层是对 RestTemplate 的封装:
-
public static JSONObject request(String url, Map<String, Object> headers, Map<String, Object> param) {
-
HttpHeaders head = new HttpHeaders();
-
if (!ObjectUtils.isNull(headers)) {
-
for (String h : headers.keySet()) {
-
head.add(h, String.valueOf(headers.get(h)));
-
}
-
}
-
// HttpUtils.useHHMApi 底层实际发起拉取数据的地方
-
String entity = restTemplate.postForObject(url, new HttpEntity<Map>(param, head), String.class);
-
return JSONObject.parseObject(entity);
-
}
在上面那段代码中,会具体发送 http 请求到另一个服务去拉取数据。对于这种场景:
- 1、需要保障用例不会受到对方服务的影响都能顺利执行。
- 2、关注的是 getUserCaseList 这个方法本身的逻辑(这里举例,代码做了相应的简化)
因此,和实际运行的逻辑不同在于,在编写测试用例时,对于底层发起的 http 调用其实不是主要关注的,可以基于约定好的成功/失败的数据报文结构,通过 mock 的方式来代替实际 http 请求发送。
-
@Test
-
public void test_getUserCaseList() {
-
// 提供 mock 条件
-
Mockito.when(restTemplate.postForObject(Mockito.any(String.class), Mockito.any(HttpEntity.class), Mockito.any(Class.class))).thenReturn(MockData.mockMiniAppUserCaseResponseData(true));
-
UserCaseRequest request = new UserCaseRequest();
-
request.setPhone("15215608668");
-
request.setPageNo(1);
-
request.setPageSize(10);
-
Response<UserCaseResponse> response = naturalService.getUserCaseList(request);
-
Assert.assertEquals("200", response.getCode());
-
}
通过这种形式,则可以有效屏蔽因为三方服务对于我们自己当前用例的影响(核心的还是要关注在自己的业务逻辑上)。
准备条件可以在 @Before 中体现
-
@Before
-
public void before() {
-
RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
-
HttpUtils.setRestTemplate(restTemplate);
-
}
SpringBootTest 说明
在 test_getUserCaseList 中,naturalService 是一个spring bean,因此执行此用例我们需要依赖 spring 容器环境。
-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
-
classes = ServerApplication.class)
-
@RunWith(SpringRunner.class)
-
public class UserCaseTest {
-
@Autowired
-
private NaturalService naturalService;
-
// your test case
-
}
@SpringBootTest 在官文档中被描述用于 integration testing 使用的注解,其目的是用于启动一个 ApplicationContext,达到在无需部署应用程序或连接到其他基础设施即可执行 集成测试。已上面的代码为例,其中:
- webEnvironment 用于描述运行环境,主要包括以下几种类型:
类型 | 描述 |
---|---|
MOCK | 这个选项不启动真正的 Web 服务器,而是使用模拟的 Servlet 上下文来运行测试。这意味着你的应用程序的 Web 层(控制器、过滤器等)将在一个模拟的环境中运行,不会实际处理 HTTP 请求和响应。这种环境适用于单元测试和切片测试,通常用于测试应用程序的业务逻辑。 |
RANDOM_PORT | 这个选项会启动一个嵌入式的 Web 服务器,并随机选择一个可用的端口。测试将通过实际的 HTTP 请求和响应与应用程序的 Web 层交互。这种环境适用于端到端测试,可以测试整个 Web 栈,包括控制器、服务、数据访问等。 |
DEFINED_PORT | 这个选项也会启动嵌入式的 Web 服务器,但它会使用一个预定义的端口号。你可以通过 server.port 配置属性来指定端口号。与 WebEnvironment.RANDOM_PORT 不同,这个选项的端口号是固定的。这对于需要在已知端口上运行测试的情况很有用。 |
NONE | 这个选项完全不启动 Web 服务器。它用于纯粹的单元测试,不涉及任何 Web 层的逻辑。在这种环境中,通常只测试应用程序的业务逻辑和服务层,不测试与 HTTP 请求和响应相关的内容。 |
- classes 属性用于指定要加载的配置类,这些配置类将用于初始化 Spring Boot 应用程序上下文。通过 classes 属性,可以控制在测试中加载的 Spring Bean 配置,以适应不同的测试需求。在上述案例中,ServerApplication.class 是当前项目的启动类,表示在测试中加载整个应用程序上下文。
- @RunWith 用于指定测试运行器(Runner),JUnit 4 默认运行器是 BlockJUnit4ClassRunner ,在 Spring 中对应的是 BlockJUnit4ClassRunner 的子类 SpringJUnit4ClassRunner,而上述代码中的 SpringRunner 和 SpringJUnit4ClassRunner 是一样的,从 SpringRunner 类的源码注释中可以看到,SpringRunner是 SpringJUnit4ClassRunner 的别名(
SpringRunner is an alias for the SpringJUnit4ClassRunner
)。
使用 H2 内存数据库来代替实际库
在编写用例时,大多数情况下,我们需要依赖数据库的数据进行场景描述;但是一般情况下,即使是测试库,用于作为测试用例的依赖也是不合适的。因此在实践过程中,一般会使用 H2 来代替实际使用的类似 Mysql 数据库来进行测试,实现数据层面的环境隔离。使用 H2 作为测试用例依赖数据库也比较简单,在 pom 中引入如下 H2 的依赖。然后在测试时指定对应 H2 的配置文件代替 Mysql 的配置文件即可,制定配置参考下一小节。
-
<dependency>
-
<groupId>com.h2database</groupId>
-
<artifactId>h2</artifactId>
-
<scope>test</scope>
-
</dependency>
使用指定的测试配置文件
如前面提到,如何我们期望测试用例的环境和实际的环境隔离,则可以使用一个单独的配置文件来描述,比如使用 H2 代替实际的数据库。
- 测试配置文件 application-test.yaml
-
spring:
-
# 使用 H2 作为数据源
-
datasource:
-
url: jdbc:h2:mem:customdb
-
driverClassName: org.h2.Driver
-
username: root
-
password: password
-
# 省略其他配置
- 指定配置文件
-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
-
classes = ServerApplication.class)
-
@RunWith(SpringRunner.class)
-
@PropertySource(value = {"classpath:application-test.yaml"})
-
public class UserCaseTest {
-
@Autowired
-
private NaturalService naturalService;
-
// your test case
-
}
做好测试资源的清理
做好测试资源清理是一个好用例具备的基本前提;如果两个研发同时需要依赖某一个表的数据进行用例设计,如果每个人都没有做好自己用例的资源清理,则在实际的用例执行过程中则会出现用例之间的相互干扰。另外,如果对于一些团队,没有使用 H2 来代替实际的测试库,那么在用例不断执行的过程中,会给测试库产生相当于的测试脏数据。基于上面两个前提,所以我们在设计用例时,特别是涉及到数据或者状态变更的场景时,一定要做好相应的资源清理。如用户注册的场景逻辑:
-
@Test
-
public void test_register(){
-
UserDto userDto = new UserDto();
-
userDto.setPhone("test number");
-
userDto.setName("test");
-
userDto.setNickName("test");
-
userDto.setPassword("test pwd");
-
// 注册用户
-
bool success = userService.register(userDto);
-
Assert.assertTrue(success);
-
}
在上面这段用例,可能会出现的情况:
- 如果用户表中没有做基于名字或者手机号的唯一性校验,则在我们的表中可能会出现很多 name 为 test 的用户。(每执行一次,则产生一条记录)
- 如果用户表做了唯一性约束,那么当第一次执行完之后,第二次执行时则可能会报错,当前用例会执行失败。
所以,在优化这个用例时,就可以将用例执行完之后的数据清除掉。具体做法有两种:
- 1、在当前用例中执行,比如通过 try finally,在 finally 块中执行删除插入的数据
- 2、在 @After 中执行删除插入的数据(@After 注解描述的方法,会在每个用例执行完之后执行,通过用于做资源清理)
小结
本篇主要针对如何编写测试用例进行了简单的介绍;包括场景的测试方式分类、测试工具;并通过几个小的测试用例对单元测试、组件测试和集成测试做了分析。最后针对日常研发中,如何做好测试编写和如何做好测试资源释放给了目前主流方案的建议和使用说明。
相关文章:

如何编写测试用例
代码质量管理是软件开发过程中的关键组成部分,比如我们常说的代码规范、代码可读性、单元测试和测试覆盖率等,对于研发人员来说单元测试和测试覆盖率是保障自己所编写代码的质量的重要手段;好的用例可以帮助研发人员确保代码质量和稳定性、减…...

复原IP地址(力扣93)
有了上一道题分割字符串的基础,这道题理解起来就会容易很多。相同的思想我就不再赘述,在这里我就说明一下此题额外需要注意的点。首先是终止条件如何确定,上一题我们递归到超过字符串长度时,则说明字符串已经分割完毕,…...

zzcms接口index.php id参数存在SQL注入漏洞
zzcms接口index.php id参数存在SQL注入漏洞 漏洞描述 ZZCMS 2023中发现了一个严重漏洞。该漏洞影响了文件/index.php中的某些未知功能,操纵参数id会导致SQL注入,攻击可能是远程发起的,该漏洞已被公开披露并可被利用。攻击者可通过sql盲注等手段,获取数据库信息。 威胁等级:…...

Redis03 - 高可用
Redis高可用 文章目录 Redis高可用一:主从复制 & 读写分离1:主从复制的作用2:主从复制原理2.1:全量复制2.2:增量复制(环形缓冲区) 3:主从复制实际演示3.1:基本流程准…...

系统URL整合系列视频四(需求介绍补充)
视频 系统URL整合系列视频四(需求补充说明) 视频介绍 (全国)大型分布式系统Web资源URL整合需求(补充)讲解。当今社会各行各业对软件系统的web资源访问权限控制越来越严格,控制粒度也越来越细。…...

激活函数篇 03 —— ReLU、LeakyReLU、ELU
本篇文章收录于专栏【机器学习】 以下是激活函数系列的相关的所有内容: 一文搞懂激活函数在神经网络中的关键作用 逻辑回归:Sigmoid函数在分类问题中的应用 整流线性单位函数(Rectified Linear Unit, ReLU),又称修正线性单元&a…...

山东大学软件学院人机交互期末复习笔记
文章目录 2022-2023 数媒方向2023-2024 软工方向重点题目绪论发展阶段 感知和认知基础视觉听觉肤觉知觉认知过程和交互设计原则感知和识别注意记忆问题解决语言处理影响认知的因素 立体显示技术及其应用红蓝眼镜偏振式眼镜主动式(快门时)立体眼镜 交互设…...

python 语音识别方案对比
目录 一、语音识别 二、代码实践 2.1 使用vosk三方库 2.2 使用SpeechRecognition 2.3 使用Whisper 一、语音识别 今天识别了别人做的这个app,觉得虽然是个日记app 但是用来学英语也挺好的,能进行语音识别,然后矫正语法,自己说的时候 ,实在不知道怎么说可以先乱说,然…...

docker常用命令及案例
以下是 Docker 的所有常用命令及其案例说明,按功能分类整理: 1. 镜像管理 1.1 拉取镜像 命令: docker pull <镜像名>:<标签>案例: 拉取官方的 nginx 镜像docker pull nginx:latest1.2 列出本地镜像 命令: docker images案例: 查看本地所有…...

DeepSeek-R1 云环境搭建部署流程
DeepSeek横空出世,在国际AI圈备受关注,作为个人开发者,AI的应用可以有效地提高个人开发效率。除此之外,DeepSeek的思考过程、思考能力是开放的,这对我们对结果调优有很好的帮助效果。 DeepSeek是一个基于人工智能技术…...

Java_双列集合
双列集合特点 存放的是键值对对象(Entry) Map 因为都是继承Map,所以要学会这些API,后面的类就都知道了 put 有两个操作,添加(并返回null)或者覆盖(返回被覆盖的值)…...

.net的一些知识点6
1.写个Lazy<T>的单例模式 public class SingleInstance{private static readonly Lazy<SingleInstance> instance new Lazy<SingleInstance>(() > new SingleInstance());private SingleInstance(){}public static SingleInstance Instace > instance…...

无须付费,安装即是完全版!
不知道大家有没有遇到过不小心删掉了电脑上超重要的文件,然后急得像热锅上的蚂蚁? 别担心,今天给大家带来一款超给力的数据恢复软件,简直就是拯救文件的“救星”! 数据恢复 专业的恢复数据软件 这款软件的界面设计得特…...

常见数据库对象与视图VIEW
常见的数据库对象 表 TABLE 数据字典 约束 CONSTRAINT 视图 VIEW 索引 INDEX 存储过程 PROCESS 存储函数 FUNCTION 触发器 TRIGGER 视图VIEW 1、引入 为什么使用视图? 视图可以帮助我们使用表的一部分,针对不同的用户制定不同的查询视图。 …...

【Vue2】vue2项目中如何使用mavon-editor编辑器,数据如何回显到网页,如何回显到编辑器二次编辑
参考网站: 安装使用参考:vue2-常用富文本编辑器使用介绍 html网页展示、编辑器回显二次编辑参考:快速搞懂前端项目如何集成Markdown插件mavon-editor,并回显数据到网页 安装命令 npm install mavon-editor2.9.1 --save全局配置 …...

2、Python面试题解析:如何进行字符串插值?
Python字符串插值详解 字符串插值是将变量或表达式嵌入字符串中的一种技术,Python提供了多种方式实现字符串插值。以下是常见的几种方法及其详细解析和代码示例。 1. 百分号(%)格式化 这是Python早期版本中的字符串插值方法,类似…...

计算机网络-SSH基本原理
最近年底都在忙,然后这两天好点抽空更新一下。前面基本把常见的VPN都学习了一遍,后面的内容应该又继续深入一点。 一、SSH简介 SSH(Secure Shell,安全外壳协议)是一种用于在不安全网络上进行安全远程登录和实现其他安…...

doris:MySQL 兼容性
Doris 高度兼容 MySQL 语法,支持标准 SQL。但是 Doris 与 MySQL 还是有很多不同的地方,下面给出了它们的差异点介绍。 数据类型 数字类型 类型MySQLDorisBoolean- 支持 - 范围:0 代表 false,1 代表 true- 支持 - 关键字&am…...

mysql 存储过程和自定义函数 详解
首先创建存储过程或者自定义函数时,都要使用use database 切换到目标数据库,因为存储过程和自定义函数都是属于某个数据库的。 存储过程是一种预编译的 SQL 代码集合,封装在数据库对象中。以下是一些常见的存储过程的关键字: 存…...

C++ 中的 cJSON 解析库:用法、实现及递归解析算法与内存高效管理
在现代软件开发中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,因其易于阅读和编写、易于机器解析和生成的特性,被广泛应用于各种场景。C 作为一种强大的编程语言,自然也需要一个高效的…...

websocket自动重连封装
websocket自动重连封装 前端代码封装 import { ref, onUnmounted } from vue;interface WebSocketOptions {url: string;protocols?: string | string[];reconnectTimeout?: number; }class WebSocketService {private ws: WebSocket | null null;private callbacks: { [k…...

【C语言】球球大作战游戏
目录 1. 前期准备 2. 玩家操作 3. 生成地图 4. 敌人移动 5. 吃掉小球 6. 完整代码 1. 前期准备 游戏设定:小球的位置、小球的半径、以及小球的颜色 这里我们可以用一个结构体数组来存放这些要素,以方便初始化小球的信息。 struct Ball {int x;int y;float r;DWORD c…...

人工智能D* Lite 算法-动态障碍物处理、多步预测和启发式函数优化
在智能驾驶领域,D* Lite 算法是一种高效的动态路径规划算法,适用于处理环境变化时的路径重规划问题。以下将为你展示 D* Lite 算法的高级用法,包含动态障碍物处理、多步预测和启发式函数优化等方面的代码实现。 代码实现 import heapq impo…...

MySQL 8版本认证问题
目录 问题: Public Key Retrieval is not allowed原因: mysql 8.0 调整身份认证机制解决方法(三种) 问题: Public Key Retrieval is not allowed 连接MySQL8数据库的时候,报错内容如下:“Publi…...

Android 开发APP中参数配置与读取总结
以使用MQTT配置的参数 MQTT_BROKER_UR 、MQTT_USER_NAME、 MQTT_PASSWORD为例,说明配置设置和读取应用 项目中使用系统参数(如环境变量和gradle.properties文件中的属性)在Gradle构建脚本中,以下是一个详细的操作文档资料&…...

Scala 语法入门
Scala语法入门 1. 定义变量2. 定义方法3. 闭包4. 声明字符串5. 声明数组6. 声明集合7. 异常处理 1. 定义变量 (变量的类型在变量名之后等号之前声明) 不可变变量(val) 类似于 Java 中的 final 变量,即一旦赋值后,其值不能再被改…...

python中的flask框架
Flask 是一个用Python编写的轻量级Web应用框架 基于WSGI和Jinja2模板引擎 被称为“微框架”,其核心功能简单,不捆绑数据库管理、表单验证等功能,而是通过扩展来增加其他功能 Flask提供最基本的功能,不强制使用特定工具或库 通…...

【redis】缓存设计规范
本文是 Redis 键值设计的 14 个核心规范与最佳实践,按重要程度分层说明: 一、通用数据类型选择 这里我们先给出常规的选择路径图。 以下是对每个步骤的分析: 是否需要排序?: zset(有序集合)用…...

归一化与伪彩:LabVIEW图像处理的区别
在LabVIEW的图像处理领域,归一化(Normalization)和伪彩(Pseudo-coloring)是两个不同的概念,虽然它们都涉及图像像素值的调整,但目的和实现方式截然不同。归一化用于调整像素值的范围,…...

DeepSeek大模型本地部署实战
1. 下载并安装Ollama 打开浏览器:使用你常用的浏览器(如Chrome、Firefox等)访问Ollama的官方网站。无需特殊网络环境,直接搜索“Ollama”即可找到。 登录与下载:进入Ollama官网后,点击右上角的“Download…...