mockito加junit实现单元测试笔记

目录

    • 一、简介
      • 1.1 单元测试的特点
      • 1.2 mock类框架使用场景
      • 1.3 常用mock类框架
        • 1.3.1 mockito
        • 1.3.2 easymock
        • 1.3.3 powermock
        • 1.3.4 JMockit
    • 二、mockito的单独使用
      • 2.1 mock对象与spy对象
      • 2.2 初始化mock/spy对象的方式
        • 初始化mock/spy对象第1种方式
        • 初始化mock/spy对象第2种方式
        • 初始化mock/spy对象第3种方式
      • 2.3 参数匹配
      • 2.4 方法插桩
        • 返回指定值
        • void返回值方法插桩
        • 插桩的两种方式
        • 抛异常
        • 多次插桩
        • thenAnswer
        • 执行真正的原始方法
        • verify的使用
      • 2.5 @InjectMocks注解的使用
      • 断言工具
    • 三、实战讲解
    • 四、mockito在springboot环境使用(不推荐)
    • 附上其他代码

此文根据视频《mockito加junit搞定单元测试》进行整理,如有侵权,联系删除。

一、简介

1.1 单元测试的特点

  • 配合断言使用(杜绝System.out) 。
  • 可重复执行 。
  • 不依赖环境 。
  • 不会对数据产生影响。
  • spring的上下文环境不是必须的 。
  • 一般都需要配合mock类框架来实现。

1.2 mock类框架使用场景

要进行测试的方法存在外部依赖(如db,redis,第三方接口调用等),为了能够专注于对该方法(单元)的逻辑进行测试,就希望能虚拟出外部依赖,避免外部依赖成为测试的阻塞项。
用到mock类框架进行虚拟这些外部依赖。
一般单元测试都是针对service层。

1.3 常用mock类框架

mock类框架:用于mock外部依赖

1.3.1 mockito

名称:ito:input to output
官网:https://site.mockito.org
官网文档:https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
限制:老版本对于final class、final method、static method、private method 均不能被 mockito mock。目前已支持final class、final method、static method 的 mock,具体可以参考官网
(39. Mocking final types, enums and final methods (Since 2.1.0))
(48. New API for mocking static methods (Since 3.4.0))

原理:bytebuddy 教程:https://www.bilibili.com/video/BV1G24y1a7bd
(通过修改字节码来实现代理的)

1.3.2 easymock
1.3.3 powermock

官网:https://github.com/powermock/powermock
与 mockito 的版本支持关系:https://gitee.com/mirrors/powermock/wikis/Mockito#supported-versions
对 mockito 或 easymock 的增强

1.3.4 JMockit

二、mockito的单独使用

2.1 mock对象与spy对象

方法插桩方法不插桩作用对象最佳实践
mock对象执行插桩逻辑返回mock对象的默认值(0 / null / 空集合)类、接口被测试类或其依赖
spy对象执行插桩逻辑调用真实方法类、接口被测试类

使用 mockingDetails 判断对象是否为 mock对象、spy 对象

2.2 初始化mock/spy对象的方式

方法一方法二方法三
junit4@RunWith(MockitoJUnitRunner.class) +@Mock等注解Mockito.mock(X.class)等静态方法MockitoAnnotations.openMocks(this)+@Mock等注解
junit5@ExtendWith(MockitoExtension.class) + @Mock等注解Mockito.mock(X.class)等静态方法MockitoAnnotations.openMocks(this)+@Mock等注解
初始化mock/spy对象第1种方式
/*** 初始化mock/spy对象有3种方式,第1种方式*/
@RunWith(MockitoJUnitRunner.class)
public class InitMockOrSpyMethod1Test {@Mockprivate UserService mockUserService;@Spyprivate UserService spyUserService;@Testpublic void test1() {// trueSystem.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());// falseSystem.out.println("Mockito.mockingDetails(mockUserService).isSpy() = " + Mockito.mockingDetails(mockUserService).isSpy());// trueSystem.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetails(spyUserService).isMock());// trueSystem.out.println("Mockito.mockingDetails(spyUserService).isSpy() = " + Mockito.mockingDetails(spyUserService).isSpy());}
}
初始化mock/spy对象第2种方式
/*** 初始化mock/spy对象有3种方式,第2种方式*/
public class InitMockOrSpyMethod2Test {private UserService mockUserService;private UserService spyUserService;@Beforepublic void init() {mockUserService = Mockito.mock(UserService.class);spyUserService = Mockito.spy(UserService.class);}@Testpublic void test1() {// trueSystem.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());// falseSystem.out.println("Mockito.mockingDetails(mockUserService).isSpy() = " + Mockito.mockingDetails(mockUserService).isSpy());// trueSystem.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetails(spyUserService).isMock());// trueSystem.out.println("Mockito.mockingDetails(spyUserService).isSpy() = " + Mockito.mockingDetails(spyUserService).isSpy());}
}
初始化mock/spy对象第3种方式
/*** 初始化mock/spy对象有3种方式,第3种方式*/
public class InitMockOrSpyMethod3Test {@Mockprivate UserService mockUserService;@Spyprivate UserService spyUserService;@Beforepublic void init() {
//        MockitoAnnotations.initMocks(this);MockitoAnnotations.openMocks(this);}@Testpublic void test1() {// trueSystem.out.println("Mockito.mockingDetails(mockUserService).isMock() = " + Mockito.mockingDetails(mockUserService).isMock());// falseSystem.out.println("Mockito.mockingDetails(mockUserService).isSpy() = " + Mockito.mockingDetails(mockUserService).isSpy());// trueSystem.out.println("Mockito.mockingDetails(spyUserService).isMock() = " + Mockito.mockingDetails(spyUserService).isMock());// trueSystem.out.println("Mockito.mockingDetails(spyUserService).isSpy() = " + Mockito.mockingDetails(spyUserService).isSpy());}
}

2.3 参数匹配

/*** 参数匹配:通过方法签名(参数)来指定哪些方法调用需要被处理(插桩、verify验证)*/
@RunWith(MockitoJUnitRunner.class)
public class ParamMatcherTest {@Mockprivate UserService mockUserService;/*** 对于mock对象,不会调用真实方法,直接返回mock对象的默认值* 默认值:0(int)、null、空集合*/@Testpublic void test1() {UserVO userVO = mockUserService.selectById(1L);
//        userVO = nullSystem.out.println("userVO = " + userVO);UserUpdateReq userUpdateReq = new UserUpdateReq();int i = mockUserService.modifyById(userUpdateReq);
//        i = 0System.out.println("i = " + i);}/*** 测试插桩时的参数匹配,只拦截userUpdateReq1*/@Testpublic void test2() {UserUpdateReq userUpdateReq1 = new UserUpdateReq();userUpdateReq1.setId(1L);userUpdateReq1.setPhone("1");Mockito.doReturn(99).when(mockUserService).modifyById(userUpdateReq1);int result1 = mockUserService.modifyById(userUpdateReq1);// result1 = 99System.out.println("result1 = " + result1);UserUpdateReq userUpdateReq2 = new UserUpdateReq();userUpdateReq2.setId(2L);userUpdateReq2.setPhone("2");int result2 = mockUserService.modifyById(userUpdateReq2);// result2 = 0System.out.println("result2 = " + result2);int result3 = mockUserService.modifyById(userUpdateReq1);// result3 = 99System.out.println("result3 = " + result3);}/*** 测试插桩时的参数匹配,ArgumentMatchers.any(UserUpdateReq.class)拦截UserUpdateReq类型的任意对象* 除了ArgumentMatchers.any(XXX.class),还有anyXXX(),例如anyString(),anyLong()...*/@Testpublic void test3() {Mockito.doReturn(99).when(mockUserService).modifyById(ArgumentMatchers.any(UserUpdateReq.class));UserUpdateReq userUpdateReq1 = new UserUpdateReq();userUpdateReq1.setId(1L);userUpdateReq1.setPhone("1");Mockito.doReturn(99).when(mockUserService).modifyById(userUpdateReq1);int result1 = mockUserService.modifyById(userUpdateReq1);// result1 = 99System.out.println("result1 = " + result1);UserUpdateReq userUpdateReq2 = new UserUpdateReq();userUpdateReq2.setId(2L);userUpdateReq2.setPhone("2");int result2 = mockUserService.modifyById(userUpdateReq2);// result2 = 99System.out.println("result2 = " + result2);int result3 = mockUserService.modifyById(userUpdateReq1);// result3 = 99System.out.println("result3 = " + result3);}/*** 测试插桩时的参数匹配,除了ArgumentMatchers.any(XXX.class),还有anyXXX(),例如anyString(),anyLong()...* 注意:anyXXX()不包括null*/@Testpublic void test4() {List<String> featureList = new ArrayList<>();featureList.add("高");featureList.add("富");mockUserService.add("zhangsan", "123", featureList);mockUserService.add("wangwu", "789", featureList);
//        mockUserService.add("zhangsan", "456", null);Mockito.verify(mockUserService, Mockito.times(1)).add("zhangsan", "123", featureList);Mockito.verify(mockUserService, Mockito.never()).add("lisi", "123", featureList);Mockito.verify(mockUserService, Mockito.times(2)).add(ArgumentMatchers.anyString(), ArgumentMatchers.anyString(), ArgumentMatchers.anyList());
//        不允许部分使用anyXXX表达式
//        Mockito.verify(mockUserService, Mockito.times(2)).add(ArgumentMatchers.anyString(), "123", featureList);}
}

2.4 方法插桩

指定调用某个方法时的行为(stubbing),达到相互隔离的目的

返回指定值
void返回值方法插桩
插桩的两种方式
  • when(obj.someMethod()).thenXxx():其中obj可以是mock对象
  • doXxx().when(obj).someMethod():其中obj可以是mock/spy对象或对无返回值的方法进行插桩
抛异常
多次插桩
thenAnswer
执行真正的原始方法
verify的使用
@RunWith(MockitoJUnitRunner.class)
public class StubTest {@Mockprivate List<String> mockList;@Mockprivate UserServiceImpl mockUserServiceImpl;@Spyprivate UserServiceImpl spyUserServiceImpl;/*** 指定返回值*/@Testpublic void testReturn() {// 方法1Mockito.doReturn("zero").when(mockList).get(0);Assert.assertEquals("zero", mockList.get(0));// 方法2Mockito.when(mockList.get(1)).thenReturn("one");Assert.assertEquals("one", mockList.get(1));}/*** void返回值方法插桩*/@Testpublic void testVoid() {// 调用mockList.clear时候什么都不做Mockito.doNothing().when(mockList).clear();mockList.clear();// 验证调用了一次clearMockito.verify(mockList, Mockito.times(1)).clear();}/*** 插桩的两种方式*/@Testpublic void testReturnMethod() {Mockito.when(mockUserServiceImpl.getNumber()).thenReturn(99);// 99System.out.println("mockUserServiceImpl.getNumber() = " + mockUserServiceImpl.getNumber());Mockito.when(spyUserServiceImpl.getNumber()).thenReturn(99);// 会打印getNumber// 再打印99// spy对象在没有插桩时候是调用真实方法的,写在when中会导致先执行一次原方法,达不到mock的目的System.out.println("spyUserServiceImpl.getNumber() = " + spyUserServiceImpl.getNumber());Mockito.doReturn(999).when(spyUserServiceImpl).getNumber();// 99System.out.println("spyUserServiceImpl.getNumber() = " + spyUserServiceImpl.getNumber());}/*** 抛出异常*/@Testpublic void testThrowException() {// 方法有返回值Mockito.when(mockList.get(ArgumentMatchers.anyInt())).thenThrow(RuntimeException.class);
//        Mockito.doThrow(RuntimeException.class).when(mockList).get(ArgumentMatchers.anyInt());try {mockList.get(4);Assert.fail();} catch (Exception e) {Assert.assertTrue(e instanceof RuntimeException);}// 方法没返回值Mockito.doThrow(RuntimeException.class).when(mockList).clear();try {mockList.clear();Assert.fail();} catch (Exception e) {Assert.assertTrue(e instanceof RuntimeException);}}/*** 多次插桩*/@Testpublic void testMultipleStub() {Mockito.when(mockList.size()).thenReturn(1).thenReturn(2).thenReturn(3);
//        Mockito.when(mockList.size()).thenReturn(1, 2, 3);Assert.assertEquals(1, mockList.size());Assert.assertEquals(2, mockList.size());Assert.assertEquals(3, mockList.size());Assert.assertEquals(3, mockList.size());}/*** 指定实现逻辑的插桩* thenAnswer可以实现对方法进行插桩,以实现自定义返回值逻辑。我们只需实现函数式接口Answer,并实现自定义返回值逻辑即可。* 泛型表示要插桩方法的返回值类型,此处我们使用String*/@Testpublic void testThenAnswer() {Mockito.when(mockList.get(ArgumentMatchers.anyInt())).thenAnswer(new Answer<String>() {@Overridepublic String answer(InvocationOnMock invocationOnMock) throws Throwable {Integer argument = invocationOnMock.getArgument(0, Integer.class);return String.valueOf(argument * 100);}});String result = mockList.get(3);Assert.assertEquals("300", result);}/*** 执行真正的原始方法*/@Testpublic void testCallRealMethod() {// 对mock对象插桩让它执行原始方法Mockito.when(mockUserServiceImpl.getNumber()).thenCallRealMethod();int mockResult = mockUserServiceImpl.getNumber();Assert.assertEquals(100, mockResult);// 不对spy对象插桩,spy对象默认就会调用真实方法int spyResult = spyUserServiceImpl.getNumber();Assert.assertEquals(100, spyResult);// 如果不想spy对象调用真实方法,则需要对它进行插桩Mockito.doReturn(999).when(spyUserServiceImpl).getNumber();spyResult = spyUserServiceImpl.getNumber();Assert.assertEquals(999, spyResult);}/*** 测试verify*/@Testpublic void testVerify() {mockList.add("one");mockList.add("two");mockList.clear();Mockito.verify(mockList).add("one");Mockito.verify(mockList, Mockito.times(1)).add("one");Mockito.verify(mockList, Mockito.times(2)).add(ArgumentMatchers.anyString());Mockito.verify(mockList, Mockito.never()).size();Mockito.verify(mockList, Mockito.times(0)).size();}
}

2.5 @InjectMocks注解的使用

  • 作用:若此注解声明的变量需要用到mock/spy对象, mockito会自动使用当前类里的mock或spy成员进行按类型或名字的注入。
  • 原理:构造器注入、setter注入、字段反射注入
@RunWith(MockitoJUnitRunner.class)
public class InjectMocksTest {// 执行test1方法报错,因为被@InjectMocks注解标注的类必须是实现类,mockito会创建对应的实例对象
//    @InjectMocks
//    private UserService userService;// 默认创建的对象就是未经过mockito处理的普通对象
//    @InjectMocks
//    private UserServiceImpl userService;//    配合@Spy注解使其变成默认调用真实方法的对象@InjectMocks@Spyprivate UserServiceImpl userService;//    使用@Mock注解注入到@InjectMocks注解对应的实例对象中
//    如果不使用@Mock注解注入userFeatureService到userService中,执行test1方法过程中,userFeatureService是null@Mockprivate UserFeatureService userFeatureService;@Testpublic void test1() {int number = userService.getNumber();Assert.assertEquals(100, number);}
}

断言工具

hamcrest:junit4中引入的第三方断言库,junit5中被移出,从1.3版本后,坐标由org.hamcrest:hamcrest-core变为org.hamcrest:hamcrest,用的少
assertj:常用的断言库
junit4原生断言
junit5原生断言

三、实战讲解

四、mockito在springboot环境使用(不推荐)

生成的对象受spring管理
@MockBean

  • 类似@Mock
  • 用于通过类型或名字替换spring容器中已经存在的bean,从而达到对这些bean进行mock的目的

@SpyBean

  • 作用类似@Spy
  • 用于通过类型或名字包装spring容器中已经存在的bean,当需要mock被测试类的某些方法时可以使用

附上其他代码

create database mockito_demo CHARACTER SET utf8mb4;
use mockito_demo;drop table if exists user;
CREATE TABLE `user` (`id` bigint NOT NULL AUTO_INCREMENT comment '主键',`username` varchar(100) NOT NULL comment '用户名称',`phone` varchar(50) NOT NULL comment '电话',PRIMARY KEY (`id`)
) ENGINE=InnoDB comment '用户表';drop table if exists user_feature;
CREATE TABLE `user_feature` (`id` bigint NOT NULL AUTO_INCREMENT comment '主键',`user_id` bigint NOT NULL comment '用户id:用户表的主键',`feature_value` varchar(150) NOT NULL comment '用户的特征值',PRIMARY KEY (`id`)
) ENGINE=InnoDB comment '用户特征表';insert into user(username, phone) values('xiaoming','12345678912');
insert into user_feature(user_id,feature_value) values(1,'abc');
insert into user_feature(user_id,feature_value) values(1,'def');
insert into user_feature(user_id,feature_value) values(1,'ghi');
@SpringBootApplication
@EnableTransactionManagement
@MapperScan("com.lm.mockito.mapper")
public class MockitoApp {public static void main(String[] args) {SpringApplication.run(MockitoApp.class);}
}
@RestController
@Validated
public class UserController {@Resourceprivate UserService userService;@GetMapping("/selectById")public UserVO selectById(@NotNull Long userId) {return userService.selectById(userId);}@PostMapping("/add")public String add(@RequestBody @Validated UserAddReq addReq) {userService.add(addReq.getUserName(), addReq.getPhone(), addReq.getFeatureValueList());return "OK";}
}
public interface UserService extends IService<UserDO> {UserVO selectById(Long userId);void add(String userName, String phone, List<String> featureValueList);int modifyById(UserUpdateReq userUpdateReq);int getNumber();
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {@Resourceprivate UserFeatureService userFeatureService;@Overridepublic UserVO selectById(Long userId) {UserDO existedEntity = getById(userId);if (existedEntity == null) {return null;}UserVO userVO = new UserVO();BeanUtil.copyProperties(existedEntity, userVO);List<UserFeatureDO> featureList = userFeatureService.selectByUserId(userId);if (CollectionUtils.isEmpty(featureList)) {return userVO;}userVO.setFeatureValueList(featureList.stream().map(UserFeatureDO::getFeatureValue).collect(Collectors.toList()));return userVO;}@Overridepublic void add(String userName, String phone, List<String> featureValueList) {UserDO userDO = new UserDO();userDO.setUserName(userName);userDO.setPhone(phone);save(userDO);List<UserFeatureDO> userFeatureDOList = featureValueList.stream().map(featureValue -> {UserFeatureDO userFeatureDO = new UserFeatureDO();userFeatureDO.setUserId(userDO.getId());userFeatureDO.setFeatureValue(featureValue);return userFeatureDO;}).collect(Collectors.toList());userFeatureService.saveBatch(userFeatureDOList);}@Overridepublic int modifyById(UserUpdateReq userUpdateReq) {UserDO userDO = new UserDO();userDO.setId(userUpdateReq.getId());userDO.setUserName(userUpdateReq.getUserName());userDO.setPhone(userUpdateReq.getPhone());boolean successFlag = updateById(userDO);return successFlag ? 1 : -1;}@Overridepublic int getNumber() {System.out.println("getNumber");return 100;}
}
public interface UserFeatureService extends IService<UserFeatureDO> {List<UserFeatureDO> selectByUserId(Long userId);
}
@Service
public class UserFeatureServiceImpl extends ServiceImpl<UserFeatureMapper, UserFeatureDO> implements UserFeatureService {@Overridepublic List<UserFeatureDO> selectByUserId(Long userId) {if (Objects.isNull(userId)) {return null;}LambdaQueryWrapper<UserFeatureDO> lqw = Wrappers.<UserFeatureDO>lambdaQuery().eq(UserFeatureDO::getUserId,userId);return list(lqw);}
}
public interface UserMapper extends BaseMapper<UserDO> {
}
public interface UserFeatureMapper extends BaseMapper<UserFeatureDO> {
}
@Data
public class UserAddReq {@NotBlankprivate String userName;@NotBlankprivate String phone;@NotEmptyprivate List<String> featureValueList;
}
@Data
public class UserUpdateReq {@NotNullprivate Long id;@NotBlankprivate String userName;@NotBlankprivate String phone;
}
@Data
public class UserVO {private Long id;private String userName;private String phone;private List<String> featureValueList;
}
@Data
@TableName("user")
public class UserDO {@TableId(type = IdType.AUTO)private Long id;private String userName;private String phone;
}
@Data
@TableName("user_feature")
public class UserFeatureDO {@TableId(type = IdType.AUTO)private Long id;private Long userId;private String featureValue;
}

在这里插入图片描述
在这里插入图片描述

真要mock私有方法,使用powermock

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

新版idea创建maven项目时的下载问题

新版idea创建时没有一个直接的maven选项 而是一个Maven Archetype选项&#xff0c;我们只需要选择它也是一样的&#xff0c;后面跟着选就行 配置国内下载源的方法如下&#xff1a; 1. 2. 3. 代码&#xff1a; <mirror> <id>alimaven</id> <name>al…

dell服务器安装PERCCLI

因在linux 系统中无法查看系统磁盘的raid级别&#xff0c;也无法得知raid状态&#xff0c;需要安装额外的包来监控&#xff0c;因是dell服务器&#xff0c;就在dell网站中下载并安装 1、下载链接&#xff1a;驱动程序和下载 | Dell 中国https://www.dell.com/support/home/zh-…

【评论送书】一本书讲透Java线程:原理与实践

摘要&#xff1a;互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀活动&#xff0c;社交平台的实时消息推送&#xff0c;还是在线视频平台的流量洪峰&#xff0c;背后都离不开多线程技术的支持。在数字化转型的过程中&#xff0c;高并发、高性能是衡量系统性能的核心指…

流程画布开发技术方案归档(G6)

&#x1f3a8; 在理想的最美好世界中&#xff0c;一切都是为最美好的目的而设。 —— 伏尔泰 如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; 一、技术选型 •从可维护性和可拓展性出发 •基本满足 1&#xff1a;链接: https://github.com/hukaibaihu/vue-org…

如何在报表工具 FastReport Cloud 中使用 ClickHouse

FastReport Cloud 是一项云服务 (SaaS)&#xff0c;旨在为您的企业存储、编辑、构建和发送报告。您的整个团队可以从世界任何地方访问这些报告&#xff0c;并且无需创建自己的应用程序。 FastReport Cloud 试用&#xff08;qun&#xff1a;585577353&#xff09;https://chat8.…

Linux C语言 39-进程间通信IPC之管道

Linux C语言 39-进程间通信IPC之管道 本节关键字&#xff1a;C语言 进程间通信 管道 FIFO 相关库函数&#xff1a;pipe、mkfifo、mknod、write、read 什么是管道&#xff1f; 管道通常指“无名管道”&#xff0c;是Unix系统中最古老的IPC通信方式。 管道的分类 管道&#…

2023下半年软件设计师 关于我用了半个月过了软件设计师这件事

前言 废话不多说、看图喽。刚可以查询、我就赶紧去查成绩 上午成绩是57分、下午成绩是45分。下午成绩刚好踩着及格线 有关备考 我是在工作之余外进行的备考、备考前前后后花了半个月。但是备考的很仓促、每天下班都要搞到十一二点。早上赶班车也在刷题&#xff0c;吃饭的时候也…

【JavaEE】生产者消费者模式

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…

期末速成数据库极简版【分支循环函数】(4)

目录 全局变量&局部变量 局部变量定义declare 局部变量赋值select 局部变量赋值select 【1】分支结构IF 【2】分支结构CASE 简单CASE语句 搜索CASE语句 【3】循环结构While 【4】系统函数 常用字符串函数 时间函数 【5】自定义函数—标量函数 函数创建 函…

如何学习Java并发编程

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 2012年我刚转行到互联网…

定义一个学生类,其中有3个私有数据成员学号、姓名、成绩,以及若于成员。 函数实现对学生数据的赋值和输出。

#include <stdio.h> // 定义学生类 typedef struct Student { int stuNum; // 学号 char name[20]; // 姓名&#xff0c;假设最长为20个字符 float score; // 成绩 } Student; // 初始化学生信息 void initializeStudent(Student *student, int num, const…

Office Tool Plus 使用教程 让个人也能轻松使用上免费的Office

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&a…

接雨水-困难

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a;输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表…

忘记PDF密码了,怎么办?

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。忘记了PDF密码该如何解密&#xff1f; PDF和office一样&#xff0c;可以对文件进行加密&#xff0c;但是没有提供恢复密码的功…

优雅草蜻蜓I即时通讯·水银版私有化部署之安卓Android端编译-02

Android 项目配置 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 使用以上Android studio版本 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 下载最低sdk最低版本28 完成后就可以导入项目(项目导入不能开VPN,会导致部分三方库…

一v一聊天

服务端 package 一对一用户;import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Vector;…

使用加密工具The Enigma Protector ,快速保护您的软件安全

我们多次被问到使用Enigma Protector保护软件免遭破解和逆向工程的最佳方法是什么&#xff1f;在这里我将解释保护常用应用程序的技巧是什么。 许多开发人员认为&#xff0c;如果他们只需单击“保护”按钮&#xff0c;保护程序就会自动完成所有操作&#xff0c;无需嵌入额外的…

【Java基础系列】JavaWeb入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

「C++」哈希表的实现(unordered系底层)

&#x1f4bb;文章目录 &#x1f4c4;前言哈希表概念哈希函数 哈希冲突闭散列开散列 &#x1f4d3;总结 &#x1f4c4;前言 unordered系列的关联式容器之所以效率比较高,是因为其底层使用了哈希结构&#xff0c;使其在查找上的时间复杂度几乎减低到了 O ( 1 ) O(1) O(1)。 哈希…

企业ERP软件定制开发的重点|app小程序网站建设

企业ERP软件定制开发的重点|app小程序网站建设 随着企业信息化程度的不断提高&#xff0c;企业资源计划&#xff08;ERP&#xff09;软件成为了现代企业管理的重要工具。然而&#xff0c;由于不同企业的业务流程、组织结构和管理模式各异&#xff0c;现有的通用ERP软件无法完全…