当前位置: 首页 > article >正文

《Spring Boot 测试框架指南:@SpringBootTest与Mockito的最佳实践》

大家好呀!👋 今天我要和大家聊聊Spring Boot测试的那些事儿。作为一名Java开发者,写代码很重要,但写测试同样重要!💯 想象一下,你建了一座漂亮的房子🏠,但如果没有质量检查,你敢住进去吗?测试就是我们的"质量检查员"!今天重点介绍两个超级明星:@SpringBootTest和Mockito,保证让你学得明明白白!😊

📚 第一章:为什么要写测试?测试有多重要?

1.1 测试的重要性

先讲个小故事📖:小明写了一个计算器程序,能算加减乘除。他自信满满地交给老师,结果老师输入"5÷0",程序直接崩溃了💥!如果有测试,这种问题早就能发现啦!

测试的好处多多:

  • 🛡️ 防错保护:提前发现bug,避免上线后出问题
  • 🔄 安全重构:改代码时不担心破坏原有功能
  • 📝 文档作用:测试用例本身就是最好的使用示例
  • 持续集成:自动化测试是CI/CD的基础

1.2 Spring Boot测试生态

Spring Boot提供了一整套测试工具:

  • 🧪 @SpringBootTest:完整应用上下文测试
  • 🎭 Mockito:模拟对象和行为
  • 🏗️ TestEntityManager:数据库测试
  • 🌐 WebTestClient:WebFlux测试
  • 🖥️ MockMvc:Web MVC测试

今天我们先重点聊聊@SpringBootTest和Mockito这对黄金搭档!✨

🚀 第二章:@SpringBootTest - 你的应用完整测试工具

2.1 什么是@SpringBootTest?

@SpringBootTest就像是给你的Spring Boot应用做全身检查👨⚕️。它会启动几乎整个应用上下文,包括所有的bean、配置、数据库连接等等。

@SpringBootTest
class MyApplicationTests {@Autowiredprivate MyService myService; // 可以自动注入真实的bean@Testvoid contextLoads() {assertThat(myService).isNotNull();}
}

2.2 @SpringBootTest的几种模式

@SpringBootTest有三种启动模式,就像汽车的档位🚗:

  1. MOCK(默认):模拟Servlet环境,不启动真实服务器

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
    
  2. RANDOM_PORT:启动真实服务器,随机端口

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    
  3. DEFINED_PORT:使用application.properties中定义的端口

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
    
  4. NONE:不提供任何Servlet环境

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
    

2.3 实际应用示例

假设我们有个用户服务:

@Service
public class UserService {@Autowiredprivate UserRepository userRepository;public User getUserById(Long id) {return userRepository.findById(id).orElseThrow(() -> new UserNotFoundException("User not found"));}
}

测试这个服务:

@SpringBootTest
class UserServiceTest {@Autowiredprivate UserService userService;@Autowiredprivate UserRepository userRepository;@Testvoid shouldGetUserById() {// 准备测试数据User testUser = new User(1L, "张三");userRepository.save(testUser);// 执行测试User result = userService.getUserById(1L);// 验证结果assertThat(result.getName()).isEqualTo("张三");}@Testvoid shouldThrowExceptionWhenUserNotFound() {assertThatThrownBy(() -> userService.getUserById(999L)).isInstanceOf(UserNotFoundException.class).hasMessageContaining("User not found");}
}

2.4 最佳实践

  1. 合理选择web环境:根据测试需求选择MOCK、RANDOM_PORT或NONE
  2. 使用@TestConfiguration:覆盖特定bean而不是全部配置
  3. 注意测试顺序:使用@DirtiesContext确保测试独立性
  4. 控制测试范围:不要过度使用@SpringBootTest,轻量级测试更高效

🎭 第三章:Mockito - 测试中的"替身演员"

3.1 什么是Mockito?

Mockito就像是电影里的替身演员🎬,它可以:

  • 创建虚拟对象(模拟对象)
  • 定义这些对象的行为
  • 验证它们是否被正确调用

为什么需要Mockito?因为单元测试应该独立!我们不希望测试UserService时,真的去调用数据库或第三方API。

3.2 Mockito核心功能

3.2.1 创建Mock对象
// 创建一个模拟的UserRepository
UserRepository mockRepo = Mockito.mock(UserRepository.class);

或者使用注解更简洁:

@Mock
private UserRepository userRepository;@BeforeEach
void setup() {MockitoAnnotations.openMocks(this); // 初始化@Mock注解
}
3.2.2 定义Mock行为
// 当调用findById(1L)时,返回预设的用户
Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(new User(1L, "张三")));// 当调用findById(999L)时,返回空
Mockito.when(userRepository.findById(999L)).thenReturn(Optional.empty());
3.2.3 验证交互
// 验证findById(1L)被调用了一次
Mockito.verify(userRepository, Mockito.times(1)).findById(1L);// 验证deleteById从未被调用
Mockito.verify(userRepository, Mockito.never()).deleteById(Mockito.anyLong());

3.3 Mockito与@SpringBootTest结合

使用@MockBean替换Spring上下文中的真实bean:

@SpringBootTest
class UserServiceMockTest {@Autowiredprivate UserService userService; // 真实服务@MockBeanprivate UserRepository userRepository; // 模拟仓库@Testvoid shouldGetUserByIdWithMock() {// 设置模拟行为Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(new User(1L, "张三")));// 调用真实服务方法User result = userService.getUserById(1L);// 验证assertThat(result.getName()).isEqualTo("张三");Mockito.verify(userRepository).findById(1L);}
}

3.4 Mockito高级技巧

3.4.1 参数匹配器
// 任何Long类型的ID
Mockito.when(userRepository.findById(Mockito.anyLong())).thenReturn(Optional.of(new User(1L, "默认用户")));// 特定条件的参数
Mockito.when(userRepository.findByName(Mockito.argThat(name -> name.length() > 5))).thenReturn(Optional.of(new User(1L, "长名字用户")));
3.4.2 抛出异常
Mockito.when(userRepository.save(Mockito.any())).thenThrow(new RuntimeException("数据库错误"));
3.4.3 连续调用不同结果
Mockito.when(userRepository.count()).thenReturn(10L)  // 第一次调用返回10.thenReturn(20L)  // 第二次返回20.thenThrow(new RuntimeException("太多调用")); // 第三次抛出异常
3.4.4 验证调用顺序
InOrder inOrder = Mockito.inOrder(userRepository);// 验证先调用findById,再调用save
inOrder.verify(userRepository).findById(1L);
inOrder.verify(userRepository).save(Mockito.any(User.class));

3.5 Mockito最佳实践

  1. 不要过度Mock:只Mock必要的依赖
  2. 验证适度:不要过度验证内部实现
  3. 保持简单:每个测试只关注一个行为
  4. 使用@Spy谨慎:@Spy是部分Mock,可能导致测试不稳定

🔧 第四章:测试中的常见问题与解决方案

4.1 测试速度慢怎么办?

@SpringBootTest启动整个应用,确实会比较慢🐢。解决方案:

  • 使用**@DataJpaTest**、@WebMvcTest等切片测试
  • 合理使用**@MockBean**减少真实bean加载
  • 共享测试上下文:@SpringBootTest + @DirtiesContext

4.2 数据库测试问题

测试时操作数据库📊要注意:

  • 使用嵌入式数据库(H2)加速测试
  • 每个测试后清理数据:
    @Transactional
    @Rollback  // 默认就是true
    @Test
    void testWithDatabase() { ... }
    
  • 或者手动清理:
    @AfterEach
    void tearDown() {userRepository.deleteAll();
    }
    

4.3 第三方服务依赖

对于外部API调用🌐:

  • 使用Mockito模拟
  • 使用WireMock模拟HTTP服务
  • 考虑契约测试(Pact)

4.4 测试Spring MVC

测试Controller层🖥️:

@WebMvcTest(UserController.class)
class UserControllerTest {@Autowiredprivate MockMvc mockMvc;@MockBeanprivate UserService userService;@Testvoid shouldReturnUser() throws Exception {Mockito.when(userService.getUserById(1L)).thenReturn(new User(1L, "张三"));mockMvc.perform(MockMvcRequestBuilders.get("/users/1")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.jsonPath("$.name").value("张三"));}
}

🏆 第五章:测试金字塔与策略

5.1 测试金字塔

健康的测试套件应该像金字塔🏛️:

  1. 单元测试(70%):测试单个类,快速执行
  2. 集成测试(20%):测试组件间交互
  3. 端到端测试(10%):测试完整应用流程

5.2 如何选择测试工具

测试类型适用场景推荐工具
纯业务逻辑Service层核心逻辑JUnit + Mockito
数据库交互Repository层@DataJpaTest + TestEntityManager
Web层Controller@WebMvcTest + MockMvc
完整流程应用启动到API调用@SpringBootTest + TestRestTemplate
客户端交互前端调用API@SpringBootTest + WebTestClient

5.3 测试命名规范

好的测试名应该像说明书📝:

  • 方法名说明测试场景和预期
  • 常用模式:[方法名]_[状态]_[预期]

例如:

@Test
void getUserById_withInvalidId_shouldThrowException() { ... }@Test
void saveUser_withValidUser_shouldReturnSavedUser() { ... }

🛠️ 第六章:实战演练 - 完整测试示例

让我们通过一个完整的用户管理系统示例来实践:

6.1 领域模型

@Entity
public class User {@Id @GeneratedValueprivate Long id;private String name;private String email;// getters/setters
}public interface UserRepository extends JpaRepository {Optional findByEmail(String email);
}

6.2 服务层

@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public User registerUser(String name, String email) {if (userRepository.findByEmail(email).isPresent()) {throw new EmailAlreadyExistsException("Email already registered");}User user = new User();user.setName(name);user.setEmail(email);return userRepository.save(user);}public User getUserByEmail(String email) {return userRepository.findByEmail(email).orElseThrow(() -> new UserNotFoundException("User not found"));}
}

6.3 完整的测试套件

6.3.1 单元测试(Service层)
class UserServiceUnitTest {private UserService userService;@Mockprivate UserRepository userRepository;@BeforeEachvoid setUp() {userService = new UserService(userRepository);}@Testvoid registerUser_withNewEmail_shouldSaveUser() {// 准备String name = "张三";String email = "zhangsan@example.com";// 模拟findByEmail返回空Mockito.when(userRepository.findByEmail(email)).thenReturn(Optional.empty());// 模拟save返回用户User savedUser = new User(1L, name, email);Mockito.when(userRepository.save(Mockito.any(User.class))).thenReturn(savedUser);// 执行User result = userService.registerUser(name, email);// 验证assertThat(result.getId()).isNotNull();assertThat(result.getEmail()).isEqualTo(email);// 验证交互Mockito.verify(userRepository).findByEmail(email);Mockito.verify(userRepository).save(Mockito.any(User.class));}@Testvoid registerUser_withExistingEmail_shouldThrowException() {String email = "exists@example.com";// 模拟已存在用户Mockito.when(userRepository.findByEmail(email)).thenReturn(Optional.of(new User()));// 执行并验证异常assertThatThrownBy(() -> userService.registerUser("任何名字", email)).isInstanceOf(EmailAlreadyExistsException.class).hasMessageContaining("Email already registered");}
}
6.3.2 集成测试(Repository层)
@DataJpaTest
class UserRepositoryIntegrationTest {@Autowiredprivate TestEntityManager entityManager;@Autowiredprivate UserRepository userRepository;@Testvoid findByEmail_whenUserExists_shouldReturnUser() {// 保存测试用户User user = new User(null, "李四", "lisi@example.com");entityManager.persist(user);entityManager.flush();// 查询Optional found = userRepository.findByEmail(user.getEmail());// 验证assertThat(found).isPresent();assertThat(found.get().getName()).isEqualTo("李四");}@Testvoid findByEmail_whenUserNotExists_shouldReturnEmpty() {Optional found = userRepository.findByEmail("nonexistent@example.com");assertThat(found).isEmpty();}
}
6.3.3 完整集成测试
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class UserSystemIntegrationTest {@LocalServerPortprivate int port;@Autowiredprivate TestRestTemplate restTemplate;@Autowiredprivate UserRepository userRepository;@AfterEachvoid tearDown() {userRepository.deleteAll();}@Testvoid fullUserRegistrationFlow_shouldWork() {// 准备注册请求Map request = new HashMap<>();request.put("name", "王五");request.put("email", "wangwu@example.com");// 调用注册APIResponseEntity response = restTemplate.postForEntity("http://localhost:" + port + "/api/users",request,User.class);// 验证响应assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);assertThat(response.getBody().getId()).isNotNull();assertThat(response.getBody().getEmail()).isEqualTo("wangwu@example.com");// 验证数据库Optional dbUser = userRepository.findByEmail("wangwu@example.com");assertThat(dbUser).isPresent();// 调用查询APIResponseEntity getResponse = restTemplate.getForEntity("http://localhost:" + port + "/api/users?email=wangwu@example.com",User.class);assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);assertThat(getResponse.getBody().getName()).isEqualTo("王五");}
}

🎯 第七章:测试覆盖率与质量门禁

7.1 测试覆盖率

测试覆盖率是衡量测试完整性的重要指标📊:

  • 行覆盖率:执行了多少百分比代码行
  • 分支覆盖率:是否覆盖了所有if-else分支
  • 变异测试:更高级的覆盖率分析

推荐阅读文章

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 什么是 Cookie?简单介绍与使用方法

  • 什么是 Session?如何应用?

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • 如何理解应用 Java 多线程与并发编程?

  • 把握Java泛型的艺术:协变、逆变与不可变性一网打尽

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 如何理解线程安全这个概念?

  • 理解 Java 桥接方法

  • Spring 整合嵌入式 Tomcat 容器

  • Tomcat 如何加载 SpringMVC 组件

  • “在什么情况下类需要实现 Serializable,什么情况下又不需要(一)?”

  • “避免序列化灾难:掌握实现 Serializable 的真相!(二)”

  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)

  • 解密 Redis:如何通过 IO 多路复用征服高并发挑战!

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”

  • Java 中消除 If-else 技巧总结

  • 线程池的核心参数配置(仅供参考)

  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)

  • Java 枚举的几个常用技巧,你可以试着用用

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • 探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)

  • 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)

相关文章:

《Spring Boot 测试框架指南:@SpringBootTest与Mockito的最佳实践》

大家好呀&#xff01;&#x1f44b; 今天我要和大家聊聊Spring Boot测试的那些事儿。作为一名Java开发者&#xff0c;写代码很重要&#xff0c;但写测试同样重要&#xff01;&#x1f4af; 想象一下&#xff0c;你建了一座漂亮的房子&#x1f3e0;&#xff0c;但如果没有质量检…...

【计算机视觉】OpenCV项目实战- Artificial-Eyeliner 人脸眼线检测

Artificial-Eyeliner 人脸眼线检测 项目介绍运行方式运行步骤常见问题及解决方法1. dlib 安装失败其他注意事项 2. 缺少 make / gcc3. **依赖库安装问题**&#xff1a;4. *人脸关键点检测失败&#xff1a;5. 眼线效果不理想&#xff1a;6. 实时处理延迟&#xff1a;7. 保存文件…...

工作总结(十二)——迁移svn单项目到gitlab上,保留历史提交记录

文章目录 前言一、目的二、操作步骤1.创建项目库2.复制历史提交者账号3.复制待迁移项目以及历史记录4.push到gitlab远程仓库 总结 前言 本系列文章主要记录工作中一些需要记录的内容 一、目的 因为一些原因&#xff0c;我需要将svn库上的某个项目迁移到公司的gitlab库管理平台…...

Flash存储器(二):SPI NAND Flash与SPI NOR Flash

目录 一.存储架构 二.接口与封装 三.特性对比 四.典型应用场景 4.1 SPI NOR Flash 4.2 SPI NAND Flash 五.技术演进与市场趋势 六.选择建议 6.1 选择SPI NOR的场景 6.2 选择SPI NAND的场景 SPI NAND Flash和SPI NOR Flash是嵌入式设备中常用的存储器。下面通过全面对…...

Git Flow

Git Flow深度解析&#xff1a;企业级分支管理实战指南 前言 在持续交付时代&#xff0c;分支策略决定团队协作效率。Git Flow作为经典的分支管理模型&#xff0c;被Apache、Spring等知名项目采用。2023年JetBrains开发者调查报告显示&#xff0c;Git Flow仍是中大型项目最常用…...

吃透LangChain(五):多模态输入与自定义输出

多模态数据输入 这里我们演示如何将多模态输入直接传递给模型。我们目前期望所有输入都以与OpenAl 期望的格式相同的格式传递。对于支持多模态输入的其他模型提供者&#xff0c;我们在类中添加了逻辑以转换为预期格式。 在这个例子中&#xff0c;我们将要求模型描述一幅图像。 …...

C++ `unique_ptr` 多线程使用

C unique_ptr 多线程使用 一、核心结论 操作同一个 unique_ptr&#xff1a;必须加锁&#xff08;所有权转移是非原子操作&#xff09;访问被管理对象&#xff1a;若对象非线程安全&#xff0c;仍需额外同步独立 unique_ptr 实例&#xff1a;不同线程操作不同实例时无需加锁 二…...

Flink介绍——实时计算核心论文之Kafka论文详解

引入 我们通过S4和Storm论文的以下文章&#xff0c;已经对S4和Storm有了不错的认识&#xff1a; S4论文详解S4论文总结Storm论文详解Storm论文总结 不过&#xff0c;在讲解这两篇论文的时候&#xff0c;我们其实没有去搞清楚对应的流式数据是从哪里来的。虽然S4里有Keyless …...

MQTTClient.c的线程模型与异步事件驱动

MQTTClient.c的线程模型与异步事件驱动 1. 多线程架构设计 MQTTClient.c通过分离网络I/O和用户逻辑线程实现异步通信&#xff0c;核心设计如下&#xff1a; sequenceDiagramparticipant 主线程 as 主线程&#xff08;用户调用&#xff09;participant 发送队列 as 发送队列pa…...

《Learning Langchain》阅读笔记3-基于 Gemini 的 Langchain如何从LLMs中获取特定格式

纯文本输出是有用的&#xff0c;但在某些情况下&#xff0c;我们需要 LLM 生成结构化输出&#xff0c;即以机器可读格式&#xff08;如 JSON、XML 或 CSV&#xff09;或甚至以编程语言&#xff08;如 Python 或 JavaScript&#xff09;生成的输出。当我们打算将该输出传递给其他…...

AI Agents系列之构建多智能体系统

&#x1f9e0; 向所有学习者致敬&#xff01; “学习不是装满一桶水&#xff0c;而是点燃一把火。” —— 叶芝 我的博客主页&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 欢迎点击加入AI人工智能社区&#xff01; &#x1f680; 让我们一起努力&#xff0c;共创…...

OJ笔试强训_1至24天

OJ笔试强训 Day01 [NOIP2010]数字统计_牛客题霸_牛客网 点击消除_牛客题霸_牛客网 两个数组的交集_牛客题霸_牛客网 Day02 牛牛的快递_牛客题霸_牛客网 最小花费爬楼梯_牛客题霸_牛客网 数组中两个字符串的最小距离__牛客网 Day03 简写单词_牛客题霸_牛客网 dd爱框框_…...

3款顶流云电脑与传统电脑性能PK战:START云游戏/无影云/ToDesk云电脑谁更流畅?

这里写目录标题 一、前言二、本地机器配置环境三、START云游戏/无影云/ToDesk云电脑配置对比3.1 START云游戏3.2 无影云个人版3.3 ToDesk云电脑 四、本地电脑与云电脑性能实战4.1 游戏场景体验4.1.1 本地电脑测试4.1.2 云电脑测试英雄联盟黑神话悟空其他游戏 4.2 主流设计场景体…...

java IO/NIO/AIO

(✪▽✪)曼波~~~~&#xff01;让曼波用最可爱的赛马娘方式给你讲解吧&#xff01;(⁄ ⁄•⁄ω⁄•⁄ ⁄) &#x1f3a0;曼波思维导图大冲刺&#xff08;先看框架再看细节哦&#xff09;&#xff1a; &#x1f4da; 解释 Java 中 IO、NIO、AIO 的区别和适用场景&#xff1a; …...

java输出、输入语句

先创建一个用于测试的java 编写程序 #java.util使java标准库的一个包&#xff0c;这里拉取Scanner类 import java.util.Scanner;public class VariableTest {public static void main(String[] args) {#创建一个 Scanner 对象Scanner scanner new Scanner(System.in);System.…...

宏基因组产品升级——抗菌肽数据库APD

抗菌肽&#xff08;Antimicrobial Peptides&#xff0c;简称AMPs&#xff09;是一类存在于多种生物体中的天然分子。它们在抵御微生物感染中扮演着重要角色&#xff0c;发挥着先天免疫反应的作用。抗菌肽功能分类广泛&#xff0c;包括&#xff1a;抗菌&#xff0c;抗生物膜&…...

大数据面试问答-Spark

1. Spark 1.1 Spark定位 "Apache Spark是一个基于内存的分布式计算框架&#xff0c;旨在解决Hadoop MapReduce在迭代计算和实时处理上的性能瓶颈。 1.2 核心架构 Spark架构中有三个关键角色&#xff1a; Driver&#xff1a;解析代码生成DAG&#xff0c;协调任务调度&a…...

线程池七个参数的含义

Java中的线程池里七个参数的以及其各自的含义 面试题&#xff1a;说一下线程池七个参数的含义&#xff1f; 所谓的线程池的 7 大参数是指&#xff0c;在使用 ThreadPoolExecutor 创建线程池时所设置的 7 个参数&#xff0c;如以下源码所示&#xff1a; public ThreadPoolExe…...

Windows suwellofd 阅读器-v5.0.25.0320

Windows suwellofd 阅读器 链接&#xff1a;https://pan.xunlei.com/s/VOO7tUkTHHTTjSe39CeVkUHbA1?pwd3ibx# OFD(Open Fixed-layout Document) &#xff0c; 数科OFD阅读器支持国标版式、可信阅读、是电子发票、电子证照&#xff0c;电子病历等电子文件理想阅读工具。 多格…...

三大等待和三大切换

三大等待 1、三大等待&#xff1a;等待的方式有三种&#xff1a;强制等待&#xff0c;隐性等待&#xff0c;显性等待。 1、强制等待&#xff1a;time.sleep(2)&#xff0c;秒 优点&#xff1a;使用简单缺点&#xff1a;等待时间把握不准&#xff0c;容易造成时间浪费或者等待时…...

告别定时任务!用Dagster监听器实现秒级数据响应自动化

在数据管道开发中&#xff0c;我们经常面临需要根据外部事件触发计算任务的场景。传统基于时间的调度方式存在资源浪费和时效性不足的问题。本文将通过Dagster的**传感器&#xff08;Sensor&#xff09;**功能&#xff0c;演示如何构建事件驱动的数据处理流程。 场景模拟&…...

一文读懂WPF系列之MVVM

WPF MVVM 什么是MVVMWPF为何使用MVVM机制WPFMVVM 的实现手段 INotifyPropertyChanged​数据绑定的源端通知​​原理 PropertyChanged事件双向绑定的完整条件常见疑惑问题 什么是MVVM 翻译全称就是 model-view-viewmodel 3部分内容 以wpf的概念角度来解释就是 数据库数据源模型…...

【Unity】打包TextMeshPro的字体

前言 在Unity中&#xff0c;TextMeshPro与常规 Text 组件相比提供了更高级的文本呈现功能&#xff0c;TextMesh Pro 可以处理各种语言&#xff0c;包括中文。我们可以轻松地在 Unity 项目中使用中文&#xff0c;而不必担心字体和布局问题。TextMeshPro需要的字体资源就需要我们…...

51单片机实验五:A/D和D/A转换

一、实验环境与实验器材 环境&#xff1a;Keli&#xff0c;STC-ISP烧写软件,Proteus. 器材&#xff1a;TX-1C单片机&#xff08;STC89C52RC&#xff09;、电脑。 二、 实验内容及实验步骤 1.A/D转换 概念&#xff1a;模数转换是将连续的模拟信号转换为离散的数字信…...

使用VHD虚拟磁盘安装双系统,避免磁盘分区

前言 很多时候&#xff0c;我们对现在的操作系统不满意,就想要自己安装一个双系统 但是安装双系统又涉及到硬盘分区,非常复杂,容易造成数据问题 虚拟机的话有经常用的不爽,这里其实有一个介于虚拟机和双系统之间的解决方法,就是使用虚拟硬盘文件安装系统. 相当于系统在机上…...

Kafka消费者端重平衡流程

重平衡的完整流程需要消费者 端和协调者组件共同参与才能完成。我们先从消费者的视角来审视一下重平衡的流程。在消费者端&#xff0c;重平衡分为两个步骤&#xff1a;分别是加入组和等待领导者消费者&#xff08;Leader Consumer&#xff09;分配方案。这两个步骤分别对应两类…...

Django之modelform使用

Django新增修改数据功能优化 目录 1.新增数据功能优化 2.修改数据功能优化 在我们做数据优化处理之前, 我们先回顾下传统的写法, 是如何实现增加修改的。 我们需要在templates里面新建前端的页面, 需要有新增还要删除, 比如说员工数据的新增, 那需要有很多个输入框, 那html…...

云轴科技ZStack入选中国人工智能产业发展联盟《大模型应用交付供应商名录》

2025年4月8日至9日&#xff0c;中国人工智能产业发展联盟&#xff08;以下简称AIIA&#xff09;第十四次全体会议暨人工智能赋能新型工业化深度行&#xff08;南京站&#xff09;在南京召开。工业和信息化部科技司副司长杜广达&#xff0c;中国信息通信研究院院长、中国人工智能…...

写论文时降AIGC和降重的一些注意事项

‘ 写一些研究成果&#xff0c;英文不是很好&#xff0c;用有道翻译过来句子很简单&#xff0c;句型很单一。那么你会考虑用ai吗&#xff1f; 如果语句太正式&#xff0c;高级&#xff0c;会被误判成aigc &#xff0c;慎重选择ai润色。 有的话就算没有用ai生成&#xff0c;但…...

AI 编程工具—如何在 Cursor 中集成使用 MCP工具

AI 编程工具—如何在 Cursor 中集成使用 MCP工具 这里我们给出了常用的MCP 聚合工具,也就是我们可以在这些网站找MCP服务 这是一个MCP Server共享平台,用户可以在上面发布和下载MCP Server配置。在这里可以选择你需要的MCP 服务。 如果你不知道你的mcp 对应的server 名称也不…...