【单元测试】测试用例编写

在你想要了解如何编写单元测试的时候,想必对于单元测试的概念和重要性都已经有了比较充足的了解。
本篇不讲概念、不说废话,仅展示一些单元测试编写的技巧和方法,希望能够帮助大家实际用起来。

计划做一个单元测试的专栏,后续补充一些关于覆盖率检查、编写效率提升、重复执行、自动执行相关的文章。
全示例代码,无需关注、无需开会员,需要的可以持续关注。

一、引言

单元测试,编程中熟知的有效工具,擅长预先发现错误、全面覆盖异常场景并助力代码重构。若你的项目面临复杂业务难以测试或旧代码维护难题,不妨尝试单元测试,它将为这些问题带来有效解决方案。当单元测试覆盖率达到一定指标后,将显著提升代码质量和项目的可持续发展能力。

二、测试框架选择

三、基本用法

被测试代码示例

@Service
public class OrderService {@Autowiredprivate ProductService productService;public void setProductService(ProductService productService) {this.productService = productService;}public Order getById(Long id) {return new Order().setId(id).setTotalAmount(BigDecimal.valueOf(15).multiply(BigDecimal.valueOf(id))).setProduct(productService.getById(id));}public void delete(Long id) {System.out.println("Order delete called.");productService.delete(id);}private String getOrderUser(Long id) {return "Order User: " + id;}public static String staticMethod() {return "Order static method called.";}
}@Service
public class ProductService {public Product getById(Long id) {return new Product().setId(id).setName("Product: " + id);}public void delete(Long id) {System.out.println("Product delete called.");}public static String staticMethod() {return "Static method called.";}}@Data
@NoArgsConstructor
@Accessors(chain = true)
public class Order {private Long id;private BigDecimal totalAmount;private Product product;private String user;public Order(Long id) {this.id = id;this.totalAmount = BigDecimal.valueOf(10).multiply(BigDecimal.valueOf(id));}
}@Data
@Accessors(chain = true)
public class Product {private Long id;private String name;}// 使用Mockito扩展
@ExtendWith(MockitoExtension.class)
public class OrderServiceTest {// 模拟掉ProductService所有方法,仅测试OrderService@Mockprivate ProductService productService;@Spy@InjectMocksprivate OrderService orderService;}
  1. 构造测试对象
    a. 实例化创建
    OrderService orderService = new OrderService();
    
    b. 依赖注入
    @Autowired
    private OrderService orderService;
    
    c. Mock创建
    // Mock注解创建
    @Mock
    private OrderService orderService;// Mock方法创建
    OrderService orderService = Mockito.mock(OrderService.class);
    
    d. Spy创建
    // Spy注解创建
    @Spy
    private OrderService orderService;// Spy方法创建
    OrderService orderService = Mockito.spy(OrderService.class);
    
  2. 构造依赖对象
    a. 依赖注入
    @Autowired
    private OrderService orderService;
    
    b. 手动设置
    OrderService orderService = new OrderService();
    // new ProductService也可以替换为Mock、Spy生成的对象
    orderService.setProductService(new ProductService());
    
    c. InjectMock注入
    // 需要注入的对象,此处可以用@Spy替换@Mock,不过需注意@Spy和@Mock对象方法调用上的区别
    @Mock
    private ProductService productService;// 依赖OrderService的被测试对象
    @InjectMocks
    private OrderService orderService;
    
  3. 模拟方法调用。以下示例可通过Junit+Mockito 进行实现。
    a. 返回特定值
    // getById本应返回id=1的Product,此处模拟返回id=2的Product
    Mockito.doReturn(new Product().setId(2L)).when(productService).getById(1L);
    Assertions.assertEquals(2L, productService.getById(1L).getId(), "应该返回Stub的值为2L!");// 验证productService.getById(1L)被调用过
    Mockito.verify(productService).getById(Mockito.anyLong());
    // 验证productService.delete(1L)未被调用过
    Mockito.verify(productService, Mockito.never()).delete(1L);
    // 验证productService.getById(1L)被调用过1次
    Mockito.verify(productService, Mockito.times(1)).getById(1L);
    
    b. 返回动态值。前三次调用时依次返回Id为1、2、3的Product对象,第4次及之后只返回Id为3的Product对象。
    Mockito.doAnswer(invocation -> {// 获取传参Long productId = invocation.getArgument(0);// 构造一个自定义的Product对象return new Product().setId(productId);
    }).when(productService).getById(Mockito.anyLong());// 断言
    Assertions.assertEquals(3L, productService.getById(3L).getId(), "传3L应返回3L");
    Assertions.assertEquals(2L, productService.getById(2L).getId(), "传2L应返回2L");
    Assertions.assertEquals(1L, productService.getById(1L).getId(), "传1L应返回1L");
    // 验证方法被调用了三次
    Mockito.verify(productService, Mockito.times(3)).getById(Mockito.anyLong());
    
    c. 每次返回不一样的值。
    // 设置3个模拟返回值
    Mockito.doReturn(new Product().setId(1L), new Product().setId(2L), new Product().setId(3L)).when(productService).getById(1L);// 断言
    // 第一次调用
    Assertions.assertEquals(1L, productService.getById(1L).getId(), "第一次调用返回1L");
    // 第二次调用
    Assertions.assertEquals(2L, productService.getById(1L).getId(), "第二次调用返回2L");
    // 第三次调用
    Assertions.assertEquals(3L, productService.getById(1L).getId(), "第三次调用返回2L");
    // 第四次调用
    Assertions.assertEquals(3L, productService.getById(1L).getId(), "第四次调用返回2L");
    // 第五次调用
    Assertions.assertEquals(3L, productService.getById(1L).getId(), "第五次调用返回2L");
    
    d. 模拟抛出异常。
    // 调用getById方法时抛出异常
    Mockito.doThrow(new InvalidParamException("Invalid Param")).when(productService).getById(1L);// 断言,方法调用抛出InvalidParamException异常
    InvalidParamException exception = Assertions.assertThrows(InvalidParamException.class, () -> productService.getById(1L), "此处应抛出异常!");
    // 此处可以拿到异常,对异常信息再次校验
    Assertions.assertEquals("Invalid Param", exception.getMessage(), "异常信息应为Invalid Param");
    
    e. 模拟调用静态方法。自Mockito 3以后,静态方法的调用不再需要依赖PowerMock。
    // 创建模拟对象
    try (MockedStatic<ProductService> mockedStatic = Mockito.mockStatic(ProductService.class)) {// 利用Stub进行返回值模拟mockedStatic.when(ProductService::staticMethod).thenReturn("Mock static method called.");// 调用静态方法String staticMethodReturn = ProductService.staticMethod();// 断言// 应该返回模拟结果Assertions.assertEquals("Mock static method called.", staticMethodReturn, "应当返回模拟结果!");// 不应该返回真实结果Assertions.assertNotEquals("Static method called.", staticMethodReturn, "不应该返回实际结果!");
    }
    
    f. 调用Mock对象真实方法。
    // 模拟返回值
    Mockito.doReturn(new Product().setId(2L)).when(productService).getById(1L);
    // 断言
    // Mock生效。返回Mock值
    Assertions.assertEquals(2L, productService.getById(1L).getId(), "调用模拟方法返回2L");
    // 验证方法被调用过至少一次
    Mockito.verify(productService, Mockito.atLeastOnce()).getById(1L);// 调用实际方法
    Mockito.doCallRealMethod().when(productService).getById(1L);
    // 断言
    // 调用真实方法,返回实际值
    Assertions.assertEquals(1L, productService.getById(1L).getId(), "调用真实方法返回1L");
    // 验证方法调用次数增加一次,为2次
    Mockito.verify(productService, Mockito.times(2)).getById(1L);
    
  4. 特殊方法模拟。借助PowerMock对私有方法、静态方法进行测试。
    测试代码示例
    // 使用PowerMockRunner进行测试
    @RunWith(PowerMockRunner.class)
    // 将静态方法、私有方法的类在这里声明
    @PrepareForTest({OrderService.class})
    public class OrderServiceTest {@Mockprivate ProductService productService;@InjectMocksprivate OrderService orderService;}
    
    a. 模拟私有方法的调用
    Long id = 1L;
    // 使用PowerMock模拟orderService方法的执行
    orderService = PowerMockito.spy(orderService);
    // 将orderService的getOrderUser方法返回值改为“Mocked order User:”
    String mockedReturn = "Mocked order User: " + id;
    PowerMockito.doReturn(mockedReturn).when(orderService, "getOrderUser", Mockito.any());
    // 调用orderService的getById方法,getById调用静态方法getOrderUser
    Order order = orderService.getById(id);
    // 验证私有方法被调用过
    PowerMockito.verifyPrivate(orderService).invoke("getOrderUser", Mockito.any());
    // 验证orderService的getOrderUser方法被调用了1次
    PowerMockito.verifyPrivate(orderService, Mockito.times(1)).invoke("getOrderUser", Mockito.any());
    // 验证order的user值为Mock的返回值
    Assertions.assertEquals(mockedReturn, order.getUser());
    
    b. 真实调用私有方法
    Long id = 1L;
    // 使用PowerMock模拟orderService方法的执行
    orderService = PowerMockito.spy(orderService);
    // 调用orderService的私有方法getOrderUser
    String orderUser = Whitebox.invokeMethod(orderService, "getOrderUser", id);
    // 验证私有方法被调用过
    PowerMockito.verifyPrivate(orderService).invoke("getOrderUser", Mockito.any());
    // 验证orderService的getOrderUser方法被调用了1次
    PowerMockito.verifyPrivate(orderService, Mockito.times(1)).invoke("getOrderUser", Mockito.any());
    // 验证order的user值为“Order User:”,未被修改
    Assertions.assertEquals("Order User: " + id, orderUser);
    
    c. 模拟静态方法的调用。这里写法有些怪,verify方法后必须再跟一次静态方法调用
    PowerMockito.mockStatic(OrderService.class);
    // 将orderService的staticMethod方法返回值改为“Mocked order static method called.”
    String mockedReturn = "Mocked order static method called.";
    PowerMockito.when(OrderService.staticMethod()).thenReturn(mockedReturn);
    // 调用静态方法
    String staticResult = OrderService.staticMethod();
    // 验证静态方法被调用过。这里写法有些怪,verify方法后必须跟一次方法调用
    PowerMockito.verifyStatic(OrderService.class);
    OrderService.staticMethod();
    // 验证静态方法被调用过1次。这里写法有些怪,verify方法后必须跟一次方法调用
    PowerMockito.verifyStatic(OrderService.class, Mockito.times(1));
    OrderService.staticMethod();
    // 验证staticResult值为Mock的返回值
    Assertions.assertEquals(mockedReturn, staticResult);
    
    d. 模拟构造方法的调用
    // 将Order对象构造方法的返回值改为2L
    Order mockOrder = new Order(2L);
    PowerMockito.whenNew(Order.class).withArguments(1L).thenReturn(mockOrder);
    // 调用Order对象构造方法
    Order mockResult = new Order(1L);
    // 验证返回值为2L
    Assertions.assertEquals(mockResult.getId(), mockOrder.getId());
    
  5. 验证方法调用。确认被模拟的依赖方法调用是否符合预期(被调用或未被调用)
    a. 验证方法从未被调用过
    // 模拟方法返回值
    Mockito.doReturn(new Product().setId(2L)).when(productService).getById(1L);
    // 调用productService的getById方法,未调用orderService的getById方法
    productService.getById(1L);
    // 验证productService的getById方法被调用过
    Mockito.verify(productService).getById(Mockito.anyLong());
    // 验证orderService的getById方法未被调用过
    Mockito.verify(orderService, Mockito.never()).getById(1L);
    
    b. 验证方法被调用过(至少一次)
    // 模拟方法返回值
    Mockito.doReturn(new Product().setId(2L)).when(productService).getById(1L);
    // 触发一次调用
    productService.getById(1L);
    // 触发第二次调用
    productService.getById(1L);// 验证方法至少被调用一次
    Mockito.verify(productService, Mockito.atLeastOnce()).getById(Mockito.anyLong());
    
    c. 验证方法被调用指定次数
    // 模拟方法返回值
    Mockito.doReturn(new Product().setId(2L)).when(productService).getById(1L);// 触发一次调用
    productService.getById(1L);
    // 验证方法至少被调用一次
    Mockito.verify(productService, Mockito.atLeastOnce()).getById(Mockito.anyLong());
    // 验证方法被调用一次
    Mockito.verify(productService, Mockito.atLeastOnce()).getById(Mockito.anyLong());// 触发第二次调用
    productService.getById(1L);
    // 验证方法被调用两次
    Mockito.verify(productService, Mockito.times(2)).getById(Mockito.anyLong());
    

四、完整实例

  1. Controller代码测试。
    a. 被测试代码
    @RestController
    @RequestMapping("/order")
    @RequiredArgsConstructor(onConstructor_ = {@Lazy})
    public class OrderController {private final OrderService orderService;@GetMapping("/{id}")public Order info(@PathVariable Long id) {return orderService.getById(id);}}
    
    b. 单元测试代码
    @WebMvcTest(OrderController.class)
    public class OrderControllerTest {@Autowiredprivate MockMvc mockMvc;@MockBeanprivate OrderService orderService;@Test@SneakyThrowspublic void testInfo() {// 期望返回的对象Order order = new Order(1L);// 对OrderService的返回值进行模拟Mockito.doReturn(order).when(orderService).getById(order.getId());// 构造一个请求MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/order/" + order.getId()).accept(MediaType.APPLICATION_JSON);// 执行请求ResultActions resultActions = mockMvc.perform(requestBuilder);// 验证Http响应状态码resultActions.andExpect(status().isOk());// 使用JsonPath验证查询到的Id为1resultActions.andExpect(MockMvcResultMatchers.jsonPath("$.id").value(order.getId()));// 获取响应对象MockHttpServletResponse response = resultActions.andReturn().getResponse();// 解析响应内容,进行复杂验证Order respObj = JSON.parseObject(response.getContentAsString(), Order.class);Assertions.assertEquals(order.getId(), respObj.getId());}}
    

注意:@MockBean 不能使用Mokicto 中的@Mock@Spy进行替换;

  1. Service代码测试。Service层代码业务逻辑复杂,需要进行全覆盖。
    a. 被测试代码
    @Service
    @RequiredArgsConstructor(onConstructor_ = {@Lazy})
    public class UserService {private final UserMapper userMapper;public Integer save(UserCreateRequest createRequest) {// 用户密码不能等于123456if ("123456".equals(createRequest.getPassword())) {throw new InvalidParamException("用户密码太简单了!");}// 检查用户是否存在User user = userMapper.selectByUsername(createRequest.getUsername());if (user == null) {// 用户不存在则进行新增return this.create(createRequest);}// 用户存在,则按照用户名进行更新// 用户密码不能包含生日this.update(user, createRequest);return user.getId();}/*** 新增用户** @param createRequest 用户创建请求* @return 用户Id*/public Integer create(UserCreateRequest createRequest) {// 用户不存在则进行新增User createValue = new User();createValue.setUsername(createRequest.getUsername());// 从老系统查询数据User oldUser = oldUserFeign.getByUsername(createRequest.getUsername());if (oldUser == null) {// 如果在老系统不存在,使用默认值填充createValue.setSex("未知");} else {// 如果在老系统存在,使用老系统用户信息进行填充createValue.setBirthday(oldUser.getBirthday());createValue.setSex(oldUser.getSex());}// 保存到数据库return userMapper.create(createValue);}/*** 更新用户** @param user          用户* @param createRequest 更新参数*/public void update(User user, UserCreateRequest createRequest) {String formatUserBirthday = user.getBirthday().replace("-", "");if (createRequest.getPassword().contains(formatUserBirthday)) {throw new InvalidParamException("用户密码不能包含生日!");}User updateUser = new User();updateUser.setUsername(createRequest.getUsername());updateUser.setPassword(createRequest.getPassword());// 更新到数据库userMapper.update(updateUser);}}
    b. 单元测试代码
    @ExtendWith(MockitoExtension.class)
    public class UserServiceTest {@Mockprivate UserMapper userMapper;@Mockprivate OldUserFeign oldUserFeign;@Spy@InjectMocksprivate UserService userService;/*** 测试使用简单密码保存用户信息* 1、验证使用简单密码创建用户时,应当抛出异常* 2、验证非简单密码创建用户,应当能够正确保存*/@Testpublic void testSaveSimplePasswd() {// 验证使用简单密码创建用户时,应当抛出异常UserCreateRequest simplePasswdRequest = new UserCreateRequest("user-01", "123456");// 执行被测试方法,并验证异常类型是否匹配InvalidParamException assertThrows = Assertions.assertThrows(InvalidParamException.class, () -> userService.save(simplePasswdRequest), "简单密码应当抛出异常");// 验证异常信息是否匹配Assertions.assertEquals("用户密码太简单了!", assertThrows.getMessage(), "简单密码异常信息不匹配!");// 抛出异常后,或许代码不应该继续执行Mockito.verify(userMapper, Mockito.never()).selectByUsername(simplePasswdRequest.getUsername());// 验证非简单密码创建用户,应当不会抛出异常UserCreateRequest normalPasswdRequest = new UserCreateRequest("user-01", "12345678");// 执行被测试方法,且不会抛出异常userService.save(normalPasswdRequest);// 未抛出异常,后续代码应当执行一次Mockito.verify(userMapper, Mockito.times(1)).selectByUsername(normalPasswdRequest.getUsername());}/*** 测试使用不存在的用户名保存用户信息,应当执行新增操作,且更新操作不会执行*/@Testpublic void testSaveNotExistUsername() {// 用户名不存在的用户请求UserCreateRequest notExistUsernameRequest = new UserCreateRequest("user-01", "12345678");// 模拟UserMapper.selectByUsername返回值Mockito.doReturn(null).when(userMapper).selectByUsername(notExistUsernameRequest.getUsername());// 模拟UserService.create方法返回值Mockito.doReturn(1).when(userService).create(notExistUsernameRequest);// 执行被测试方法Integer createdUserId = userService.save(notExistUsernameRequest);// 未抛出异常,UserMapper.selectByUsername应当执行一次Mockito.verify(userMapper, Mockito.times(1)).selectByUsername(notExistUsernameRequest.getUsername());// 未抛出异常,UserService.create应当执行一次Mockito.verify(userService, Mockito.times(1)).create(notExistUsernameRequest);// 用户不存在,UserService.update方法不应该被执行Mockito.verify(userService, Mockito.never()).update(Mockito.any(), Mockito.any());// UserService.create返回1,UserService.save返回值也应当为1Assertions.assertEquals(1, createdUserId, "新增用户Id应该为1!");}/*** 验证使用已存在的用户名保存用户信息,应当执行更新操作,且新增操作不会被执行*/@Testpublic void testSaveExistUsername() {User user = new User().setId(1);// 用户名存在的用户请求UserCreateRequest existUsernameRequest = new UserCreateRequest("user-01", "12345678");// 模拟UserMapper.selectByUsername返回值Mockito.doReturn(user).when(userMapper).selectByUsername(existUsernameRequest.getUsername());// 模拟UserService.update调用,但是没有返回值Mockito.doNothing().when(userService).update(Mockito.any(), Mockito.any());// 执行被测试方法Integer updateUserId = userService.save(existUsernameRequest);// 未抛出异常,UserMapper.selectByUsername应当执行一次Mockito.verify(userMapper, Mockito.times(1)).selectByUsername(existUsernameRequest.getUsername());// 用户存在,UserService.create方法不应该被执行Mockito.verify(userService, Mockito.never()).create(Mockito.any());// 未抛出异常,UserService.update应当执行一次Mockito.verify(userService, Mockito.times(1)).update(Mockito.any(), Mockito.any());}}

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

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

相关文章

一文详解选择低代码开发平台的六大理由

在当今快节奏的数字时代&#xff0c;企业需要快速开发和部署应用程序以保持竞争力。传统编程方式耗时较长&#xff0c;且需要大量人力和物力投入。因此&#xff0c;低代码开发平台应运而生&#xff0c;它可以帮助企业快速构建应用程序&#xff0c;提高生产力。本文将为您阐述选…

oracle发送http请求

UTL_HTTP包让SQL和PLSQL能够调用超文本传输协议&#xff08;HTTP&#xff09;&#xff0c;也就是说可以使用它在Internet上访问数据。 当包用HTTPS从Web site获取数据时&#xff0c;要使用Oracle Wallet&#xff0c;它是由Oracle Wallet Manager或者orapki utility创建。非HTT…

Web应用安全测试-防护功能缺失

Web应用安全测试-防护功能缺失 1、Cookie属性问题 漏洞描述&#xff1a; Cookie属性缺乏相关的安全属性&#xff0c;如Secure属性、HttpOnly属性、Domain属性、Path属性、Expires属性等。 测试方法&#xff1a; 通过用web扫描工具进行对网站的扫描&#xff0c;如果存在相关…

TCP协议为啥会有三次挥手(close、shutdown)

一、前言 使用wireshrak抓包的时候&#xff0c;发现有的TCP断开连接&#xff0c;有的是三次挥手、有的是四次挥手&#xff0c;本文将带领带领大家一探究竟。 1. 四次挥手&#xff1a; 四次挥手流程回顾 第一次挥手&#xff1a; 主动关闭的一方&#xff08;客户端或服务器&…

算法安全自评估报告如何填写?(附模板)

之前&#xff0c;众森企服给大家讲过办理互联网信息服务算法备案有三部分组成&#xff1a;主体备案、算法备案和产品备案。 主体备案主要审查的就是一家主体公司是否有算法相应的规章制度&#xff0c;里面最主要的就是算法安全管理制度。 算法备案主要审查的就是算法本身的情…

【春秋云镜】Faculty Evaluation System未授权任意文件上传漏洞(CVE-2023-33440)

因为该靶场没有Write up,索性自己搞一下&#xff0c;方便别人&#xff0c;快乐自己&#xff01; 漏洞概述&#xff1a; Sourcecodester Faculty Evaluation System v1.0 is vulnerable to arbitrary code execution via /eval/ajax.php?actionsave_user. 漏洞复现&#xff…

simdjson 高性能JSON解析C++库

simdjson 是什么 simdjson 是一个用来解析JSON数据的 C 库&#xff0c;它使用常用的 SIMD 指令和微并行算法来每秒解析千兆字节的 JSON&#xff0c;在Velox, ClickHouse, Doris 中均有使用。 加载和解析 JSON documents 出于性能考虑&#xff0c;simdjson 需要一个末尾有几个…

2024年高考:计算机相关专业前景分析与选择建议

2024年高考结束&#xff0c;面对计算机专业是否仍具有吸引力的讨论&#xff0c;本文将从行业趋势、就业市场、个人兴趣与能力、专业选择建议等多个角度进行深入分析&#xff0c;以帮助考生和家长做出明智的决策。 文章目录 一、行业趋势与就业市场1. 计算机行业的发展与变革2. …

49.Chome浏览器有三种清缓存方式

49.Chome浏览器有三种清缓存方式&#xff1a;正常重新加载、硬件重新加载、清空缓存并硬性重新加载 1、【正常重新加载】 触发方式&#xff1a;①F5  ②CtrlR  ③在地址栏上回车  ④点击链接 如果缓存不过期会使用缓存。这样浏览器可以避免重新下载JavaScript文件、图像、…

LINUX 精通 3.2

main里怎么实现 accept_cb 里的regist部分抽出来 // regist拉出来 int event_register(int fd, int event) {if (fd < 0) return -1;conn_list[fd].fd fd;conn_list[fd].r_action.recv_callback recv_cb;conn_list[fd].send_callback send_cb;memset(conn_list[fd].rbuff…

【吉林大学Java程序设计】第8章:IO流

第8章&#xff1a;IO流 1.流与相关类1.1 流的概念1.2 File类1.3 字节流及其方法1.4 字符流及其方法1.5 其他IO流&#xff08;1&#xff09;节点流&#xff08;2&#xff09;处理流&#xff08;过滤流&#xff09;&#xff08;3&#xff09;文件流基于字节的文件流基于节符的文件…

Shell脚本(.sh文件)如何执行完毕之后不自动关闭?

Shell脚本异常傲娇&#xff0c;出错后、执行完根本不给你机会让你查看报错信息、输出信息&#xff0c;直接闪退。 废话不多说&#xff0c;调教方法如下&#xff0c;直接在Shell脚本末尾加上如下代码&#xff1a; 1、实现方式一 1.1 使用read命令达到类似bat中的pause命令效果…

深度解析响应式异步编程模型

上一篇文章中我们聊了一下线程池,基于线程池的多线程编程是我们在高并发场景下提升系统处理效率的有效手段,但却不是唯一的。今天我们来看一下另一种异步开发的常用手段-响应式编程模型 传统多线程模型的缺陷 多线程模型是目前应用最为广泛的并发编程手段,但凡遇到什么性能…

语义分割——mmsegmentation框架使用

目录 1.mmsegmentation简介 2.mmsegmentation安装 3.mmsegmentation使用&#xff08;代码结构介绍&#xff09; 4.mmsegmentation使用实战&#xff08;deeplab v3为例&#xff09; 4.1配置 4.2训练&#xff1a; 4.3预测&#xff1a; 1.mmsegmentation简介 mmsegmentatio…

LogicFlow 学习笔记——11. 对齐线 和 键盘快捷键

对齐线 Snapline 对齐线能够在节点移动过程中&#xff0c;将移动节点的位置与画布中其他节点位置进行对比&#xff0c;辅助位置调整。位置对比有如下两个方面。 节点中心位置节点的边框 对齐线使用 普通编辑模式下&#xff0c;默认开启对齐线&#xff0c;也可通过配置进行关…

自己想要公开自己的学习方法,但是自己很害怕自己的学习方法是一个错误的,因为对于自己而言,专升本的机会只有一次

分享自己的学习方法可能需要一定的勇气&#xff0c;特别是当你担心可能会受到批评或是不被理解时。以下是一些建议&#xff0c;可以帮助你克服这种恐惧&#xff1a;&#xff08;kimi编辑器自己对于这些内容的基础批注&#xff09; 自我肯定&#xff1a;首先&#xff0c;认识到你…

安裝了windows,Ubuntu双系統,windows系統时间不对的修正方法

当你在电脑上安装双系统(如 Windows 和 Ubuntu)时,系统时间不同步的问题通常是由于这两个操作系统处理系统时间的方式不同而引起的。Windows 默认使用本地时间(Local Time),而 Ubuntu 和其他基于 Linux 的系统通常使用协调世界时(UTC)。 为了解决这个问题,可以选择让…

小程序开发的费用简介篇

小程序的价格跟很多因素有关系&#xff0c;比如你想要的复杂度、功能多不多等等 今天我就来具体说说开发一款APP&#xff0f;小程序到底需要多少 ❶功能复杂度&#xff1a;功能越多越复杂&#xff0c;开发时间和费用就越高&#xff0c;费用就会高 ❷设计要求&#xff1a;高级的…

RAG系列之:深入浅出 Embedding

RAG系列之&#xff1a;深入浅出 Embedding 什么是文本向量化&#xff1f; 文本向量化就是将文本数据转成数字数据&#xff0c;例如&#xff1a;将文本 It was the best of times, it was the worst of times. 转成 [0, 1, 0, 2, 2, 2, 2, 2, 0, 1]。 为什么要进行文本向量化…

深入Linux Core文件生成与自定义命名规则

Linux 作为广泛使用的运行平台&#xff0c;在程序运行崩溃时能及时记录 错误信息&#xff0c;是很方便的查询问题的方式&#xff0c;这里对怎么使用 Linux下的 错误信息记录 core文件&#xff0c;进行总结介绍。 引言 在Linux系统开发中&#xff0c;当程序发生崩溃时&#xf…