單元測試學習+AI輔助單測

標題

  • 單元測試
    • 衡量指標
    • 具體測試
      • 1、@Resource
      • 2、@MockBean
      • 3、@Test
      • 4、Test模板
      • 5、單測示例
    • H2數據庫+JSON
      • 1、使用方式
    • AI輔助單測
      • 使用方法

單元測試

單元測試一般指程序員在寫好代碼后,提交測試前,需要驗證自己的代碼是否可以正常工作,同時將自己的代碼邏輯驗證放入到項目中,方便驗證后續新需求的代碼不會影響到本次需求的邏輯

基本原則:
單測應該是不依賴于任何外部依賴(如MySQL、Redis、RabbitMQ等),在自己本地可以直接執行的代碼。其中外部數據讀取以及RPC調用,應該在單測中進行模擬,而不是實際進行調用。

衡量指標

在實際開發過程種,往往會嚴格規定了測試的行覆蓋率和分支覆蓋率,對代碼有嚴格要求的大廠,會硬性規定提交代碼的覆蓋率,如果覆蓋率過低,會被拒絕部署上線。

  • 行覆蓋率:被測試執行到的行數÷可執行總數
  • 分支覆蓋率:被執行的分支÷總分支
    其中,分支覆蓋率指的是在整個測試過程中,覆蓋的分支數量。如下:
func1(a,b){if(a>1){return 1;}else{return 0;}if(b>1){return 1;}else{return 0;}
}

只需要傳入(a=1,b=1),(a=2,b=2),就要達到分支覆蓋率100%,而不需要分別傳入四次進行測試。

具體測試

在上面的介紹中,應該知道了單測是不應該進行外部依賴的,那涉及的數據以及RPC調用函數應該如何進行模擬呢?這里剛好有一些好框架可以用來很方便的進行測試,我這里以Junit5+mockit為例進行介紹。

  • Junit5
    Junit5是一套用來單測的框架,主要功能是幫助用戶簡化測試流程。當需要進行測試的時候,如果不依賴框架,就需要自己寫main函數,每個運行單元都需要有自己的main函數,并且所有的日志都需要自己進行管理,非常不方便。而Junit和Idea進行了集成,使得測試可以直接點箭頭來測試具體的函數,并且有詳細的日志報告。
  • mockit
    在測試的過程中,需要對外部依賴進行模擬,這里采用最常用的mockit進行mock,支持對Spring的Bean等等進行mock。
    這里可以給一個簡單的示例:
@Resource
OrderService orderServiceImpl;@MockBean
goodsRepository goodsRepository;@Test
public void testOrderService(){// arrange。。。//act。。。//assertResult。。。
}

幾乎所有的單測都可以按照這個結構編寫。第一次看到整個接口可能有點蒙,接下來我大概介紹一下大概的意思。

1、@Resource

同Spring的依賴注入,這里不做重復介紹。這個注解聲明的類,就是接下來要測試的類。

2、@MockBean

MockBean是Spring中Bean的模擬,這里的注解只是聲明的意思,表示這個接下來這個函數由測試類進行代理,他使用到的方法需要在后面進行聲明。

3、@Test

這個注解需要注釋在函數上,表示測試的基本單元。比如訂單服務中,有可正常情況,也有可能漏傳參數的情況,也有可能傳了錯誤參數的情況。這些需要在三個函數中進行測試,每個函數都標記@Test,分別可以獨立運行。

@Test
public void testOrderService_normal(){// ...
}@Test
public void testOrderService_nullId(){// ...
}@Test
public void testOrderService_errorId(){// ...
}

4、Test模板

可以看到每個@Test函數,都按照統一的模板進行編寫,這個也是測試的要求,需要增加測試代碼的可讀性。

  • arrange:安排的意思,這里的意思做一些前置準備,對必要的數據、函數進行實際的模擬。這里使用Mockit舉一個簡單的例子。
// arrange 不管傳入什么id,都返回null,表示數據不存在
when(goodsRepository.searchById(anyInt())).thenReturn(null);
  • act:行動的意思,這里的意思是開始執行邏輯,往往只有一行代碼
// act 搜索貨物是否還有庫存,并創建一個訂單,這里假設貨物單號為11000
result = orderServiceImpl.create(11000);
  • assertResult:驗證結果的意思,這里需要使用assert來判斷結果是否符合預期。
Assert.assertNotNull(result);
Assert.assertEqual(result.getCode(),0);
Assert.assertEqual(result.getMsg(),"");

驗證階段一般不允許使用print進行手動驗證,這是因為當項目變得龐大時,手動驗證的工作量會變得極為龐大,并且測試的結果往往是確定的,所有可以使用Assert進行驗證。

5、單測示例

這里給一個最終的模板,可以看看效果

Class OrderTest{@ResourceOrderService orderServiceImpl;@MockBeangoodsRepository goodsRepository;@Testpublic void testOrderService_normal(){// arrange,這里假設訂單創建需要調用goodsRepository服務去查詢MySQL數據庫Goods goods = new Goods(11000,"cup",15);when(goodsRepository.searchById(anyInt())).thenReturn(goods);// actresult = orderService.create(11000);// assertResult,這里假設訂單創建成功時,會返回狀態碼為0,以及message=“success”Assert.assertNotNull(result);Assert.assertEqual(result.getCode(),0);Assert.assertEqual(result.getMsg(),"success");}@Testpublic void testOrderService_nullId(){// 同理}@Testpublic void testOrderService_errorId(){// 同理}
}

H2數據庫+JSON

看完上面的內容,可以發現不管多么復雜的單測,最終都可以拆分為上面的三個部分
同時,為了更高效了進行模擬,減少代碼的侵入性,也可以采用JSON文件來模擬數據庫,不然每次模擬repository服務,都需要手動在代碼里面建立一個對象并手動賦值。所以,H2數據庫配合JSON被引入了單測
這里也很簡單,首先需要在Spring項目中引入依賴,并在application文件中進行配置,這里不贅述了,可以去網上搜一搜。

1、使用方式

H2原生不支持直接將Json轉化為數據表。一般大型公司會有自己內部的二開框架。一般是在測試方法上加一個注解,然后就當成數據表訪問。

	@Test@H2Data("dataset/goods.json") //這里只是給個示例,實際并不存在這個注解public void testOrderService_normal(){// arrange,這里假設訂單創建需要調用goodsRepository服務去查詢MySQL數據庫Goods goods = new Goods(11000,"cup",15);when(goodsRepository.searchById(anyInt())).thenReturn(goods);// actresult = orderService.create(11000);// assertResult,這里假設訂單創建成功時,會返回狀態碼為0,以及message=“success”Assert.assertNotNull(result);Assert.assertEqual(result.getCode(),0);Assert.assertEqual(result.getMsg(),"success");}

還有第二種方式,就是自己寫SQL,這樣需要維護一個SQL文件,當測試啟動時,這個SQL文件會被導入到H2數據庫中,但是H2是內存數據庫,所以在測試結束了,H2中的數據會被全部清空。

AI輔助單測

由上文可知,單測的寫法是有固定的模板的,且代碼行數涉及不多,可以使用AI來進行輔助設計。
相信很多人都用AI寫過單測,但是發現效果特別差,基本上能用的只有框架,里面的邏輯,以及mock全部都要大改,所以AI寫單測效率提升也很低。后面經過我琢磨,發現這個問題是由于我每次寫單測時,給GPT描述的語言不夠明確,希望他可以自己看代碼去進行生成。(但是當規則不明確時,AI是傾向于偷懶的)
所以搞了一個prompt,可以參考這個規則,基于自己的項目特征改改,就可以實現較高的效率了。
目前我的情況是 :需要改JSON數據文件以及極少量代碼,就可以實現目標單測邏輯

使用方法

首先需要編寫rule.md文件,然后將這個文件放在ai可以閱讀到的地方。然后使用如下詢問順序:

1、仔細閱讀rule.md文件,后續寫單元測試會用到。
2、幫我完成xx接口的單測
3、。。。(如果有完成的不好的地方,可以讓他改經,但是推薦自己改)

具體的rule文件如下,需要根據自己的項目,填充一些空缺的地方。

---
description: 單元測試|unit test|單測
globs:
alwaysApply: true
---
# 單元測試**根本原則:單元測試以接口為單位,需要驗證接口及涉及到的調用函數的執行邏輯,除非方法內部直接涉及到RPC調用、MQ調用,否則不允許mock**## 注意事項- 編寫單元測試代碼時需要注意import新增加的類或方法
- 編寫單元測試代碼過程中,**禁止更改業務代碼**
- **只允許模擬本系統的外部依賴調用,對其余方法進行mock會被懲罰**
- 強烈推薦模仿xxx.java進行單測編寫
- **查詢數據庫邏輯必須使用H2數據庫實現**## 數據準備對于請求參數類、返回參數類的構建應該進行抽象,避免出現大量的參數類構建的重復代碼。舉例如下:private Order buildOrder() {// Order組裝
}## 測試執行### 模版使用需要使用arrange、act、assertResult三段式架構編寫(簡單場景可選擇不使用,如基礎的參數校驗驗證),需要注意使用測試模版的方法需要在方法簽名上加throws Exception。模版的使用需要遵循一下規范,**不得在act中驗證結果**- arrange: 負責資源的準備,包括請求的參數構建、mock結果返回、預期返回結果構建
- act: 待測試的方法執行
- assertResult: 測試結果驗證如下所示:
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;import static org.mockito.Mockito.*;public class DemoTest{@InjectMocksprivate Demo demo;@Mockprivate UserService userService;@Mockprivate EmailClient emailClient;private User buildUser() {// User組裝...}@Testpublic void testSendEmail_UserNotFound() throws Exception {}@Overrideprotected void act() {}@Overrideprotected void assertResult() {});}
}在模版使用內部類中,常量的定義需要增加final關鍵字// goodcase: 使用final關鍵字private final Integer pageNum = 1;// badcase: 未使用final關鍵字private Integer pageSize = 10;@Overrideprotected void arrange() {// do something}@Overrideprotected void act() {// do something}@Overrideprotected void assertResult() {// do something}
### RPC操作的mock測試接口對外部進行RPC調用時,具有非常明顯的架構,比如:xxx測試接口中**具備上述調用特征的RPC調用函數都需要進行mock**### DAO層測試DAO層使用H2代替數據庫進行測試增刪改查測試,**所有的測試類中通過Repository讀取數據庫的操作,都需要你新建SQL文件進行存儲,不允許進行Mock**。#### 數據庫初始化配置datasource.xml。可根據實際情況調整。優先復用工程內已有的配置,沒有再新增。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:p="http://www.springframework.org/schema/p"xmlns="http://www.springframework.org/schema/beans" xmlns:jdbc="http://www.springframework.org/schema/jdbc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"><jdbc:embedded-database id="h2TestDataSource" type="H2" database-name="h2TestDataSource;DATABASE_TO_UPPER=TRUE;MODE=MYSQL;"><!-- 這里的 h2/init.sql 是要初始化表結構的文件 --><jdbc:script location="classpath:h2/init.sql"/></jdbc:embedded-database><!--  sqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="h2TestDataSource"/><!-- 配置 Mybatis 配置文件的位置 --><property name="configLocation" value="classpath:mybatis-config.xml"/><property name="mapperLocations"><list><!-- 這里的 value 要替換成真實的 MybatisMapper 文件地址 --><value>classpath:mapper/**/*DAO.xml</value></list></property></bean><bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg ref="sqlSessionFactory"/></bean><!-- 配置掃描 Mapper 接口的包路徑 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"p:dataSource-ref="h2TestDataSource"/><tx:annotation-driven />
</beans>#### mybatis配置mybatis-config.xml(僅供參考,優先使用項目本身的配置)<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><setting name="cacheEnabled" value="false"/><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/><setting name="multipleResultSetsEnabled" value="true"/><setting name="useColumnLabel" value="true"/><setting name="defaultExecutorType" value="SIMPLE"/><setting name="defaultStatementTimeout" value="25000"/><setting name="mapUnderscoreToCamelCase" value="true"/><setting name="useGeneratedKeys" value="true"/><setting name="logImpl" value="LOG4J2" /></settings>
</configuration>#### 數據庫表初始化h2/init.sqlCREATE TABLE IF NOT EXISTS users (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`status` tinyint(4) NOT NULL DEFAULT 1,`ctime` int(11) NOT NULL DEFAULT '0',`utime` int(11) NOT NULL DEFAULT '0',`valid` tinyint(4) NOT NULL DEFAULT 1PRIMARY KEY (`id`)
);#### 測試數據準備測試數據的生成格式如下,但是每張相關表你只允許**仿照Dao層的Vo**生成一條數據,稍后會由用戶進行具體數據的填充。datasets/user/users.json{"users": [{"id": 1,"name": "Alice","status": 1,"ctime": 1744856001,"utime": 1744856001,"valid": 1},{"id": 2,"name": "Bob","status": 2,"ctime": 1744856001,"utime": 1744856001,"valid": 1}]
}#### 示例被測試類public interface UserMapper {User getUserById(@Param("id") Long id);User getUserByName(@Param("name") String name);User save(@Param("user") User user);int updateStatusById(@Param("id") Long id, @Param("status") Integer status);
}### 私有方法測試優先通過公有方法來測試私有方法的行為,特殊場景可通過Spring提供的`ReflectionTestUtils`工具類進行私有方法的測試。> 特殊場景舉例:在無單元測試代碼的存量代碼上增加了一個邏輯分支,這時想通過公用方法來做單測的話,需要編寫這個公有方法歷史邏輯的單元測試代碼,此時可考慮直接測新增的私有方法。#### 注意事項1. **謹慎使用**:私有方法測試應該是例外而非常規做法。優先考慮通過公有方法間接測試私有方法。2. **參數類型匹配**:`invokeMethod`方法的參數必須與私有方法的參數類型完全匹配。對于基本類型和包裝類型,需要特別注意類型轉換。3. **方法名稱準確**:確保提供的方法名稱字符串與實際的私有方法名稱完全一致。4. **重載方法**:如果測試的私有方法有重載版本,`ReflectionTestUtils`會根據提供的參數類型選擇匹配的方法。## 結果驗證需要充分驗證測試結果,包括返回參數驗證、異常信息驗證、下游方法調用情況驗證。### 返回參數驗證對于返回結果的驗證需要直接驗證整個結果類:**goodcase:**1. 比較實現了equals方法的類: 通過@Data/@EqualsAndHashCode或手動實現equals方法,直接比較兩個對象是否相等`Assert.assertEquals(expected, result);`
2. 比較未實現equals方法的類: 使用json工具轉為json字符串進行比較`Assert.assertEquals(gson.toJson(expected), gson.toJson(result));`
3. 比較集合類(List,Set,Map): Set,Map直接比較整個集合類,List需要注意元素的順序,不關心返回結果順序的場景可以先排序后驗證。**badcase:**1. **不允許**通過返回對象的字段驗證: 通過逐一驗證返回的字段來驗證,這樣做容易遺漏字段Assert.assertEquals(123, result.getUserId());
Assert.assertEquals("abac", result.getUserName());
Assert.assertEquals(0, result.getCode());
Assert.assertEquals("success", result.getMessage());2. **不允許**集合類結果只驗證size: 集合類的返回只驗證了返回結果集的size,而不驗證具體的內容。如下所示:public class DemoTest extends BaseJunitTest {@InjectMocksprivate Demo demo;@Mockprivate UserService userService;@Mockprivate EmailClient emailClient;private User buildUser() {// User組裝...}private SendEmailParam buildSendEmailParam() {// EmailParam組裝...}private SendEmailResult buildSendEmailResult() {// EmailResult組裝...}@Testpublic void testSendEmail() throws Exception {TestHandleTemplate.test(new TestCallBack("測試發送郵件") {private SendEmailParam param;private SendEmailResult result;@Overrideprotected void arrange() {User user = buildUser();param = buildSendEmailParam();when(userService.getByUserId(param.getUserId())).thenReturn(user);}@Overrideprotected void act() {result = demo.sendEmail(param);}@Overrideprotected void assertResult() {SendEmailResult expected = buildSendEmailResult();// goodcase: 直接通過equals驗證整個結果類(針對實現了equals方法的類)Assert.assertEquals(expected, result);// goodcase: 比較序列化后的json字符串Assert.assertEquals(gson.toJson(expected), gson.toJson(result));// badcase: 對結果類的字段逐一驗證Assert.assertEquals(123, result.getUserId());Assert.assertEquals("abac", result.getUserName());Assert.assertEquals(0, result.getCode());Assert.assertEquals("success", result.getMessage());}});}
}### 異常驗證對于拋出異常類型的校驗需要使用assertThrows來獲取異常,并校驗異常類型與message。assertThrows方法常見與兩個包,結合所在工程使用情況來選用:1. org.testng.Assert.assertThrows
2. org.junit.jupiter.api.Assertions.assertThrows示例如下:@Test
public void testSendEmail_UserNotFound() throws Exception {TestHandleTemplate.test(new TestCallBack("測試用戶不存在") {private SendEmailParam param;private IllegalArgumentException exception;@Overrideprotected void arrange() {param = buildSendEmailParam();when(userService.getByUserId(param.getUserId())).thenReturn(null);}@Overrideprotected void act() {exception = assertThrows(IllegalArgumentException.class,() -> demo.sendEmail(param));}@Overrideprotected void assertResult() {assertEquals("用戶不存在", exception.getMessage());}});
}### 下游方法調用驗證對于下游方法的調用需驗證調用次數以及調用的入參是否符合預期。如下所示@Test
public void testSendEmail() throws Exception {TestHandleTemplate.test(new TestCallBack("測試發送郵件") {private SendEmailParam param;private SendEmailResult result;@Overrideprotected void arrange() {User user = buildUser();param = buildSendEmailParam();when(userService.getByUserId(param.getUserId())).thenReturn(user);}@Overrideprotected void act() {result = demo.sendEmail(param);}@Overrideprotected void assertResult() {verify(userService).getByUserId(eq(param.getUserId()));verify(emailClient).send(eq(buildSendEmailReq()));// 調用次數驗證...// 結果驗證...}});
}
## tips為了更好的幫助你完成單測編寫需求,我偷偷給你準備了一些小tips- 想一想,如果涉及到數據庫讀取數據操作,你會如何辦?
- 仔細閱讀xxx.java代碼,**記住這個測試代碼的風格,以及非必要不mock原則**
- 多次強調**必須使用@DataSet注解模擬所有數據庫訪問**,記住哦!
- 最后需要生成readme.md文件來記錄你的測試思路好的,你已經是一個成熟的單測輔助AI了,我相信你可以勝任接下來的單測編寫工作,如果寫的好,我會給你獎勵

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89554.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89554.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89554.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Cloud Gateway與Envoy Sidecar在微服務請求路由中的架構設計分享

Spring Cloud Gateway與Envoy Sidecar在微服務請求路由中的架構設計分享 在現代微服務架構中&#xff0c;請求路由層承擔著流量分發、安全鑒權、流量控制等多重職責。傳統的單一網關方案往往面臨可擴展性和可維護性挑戰。本文將從真實生產環境出發&#xff0c;分享如何結合Spri…

GitHub Pages+Jekyll 靜態網站搭建(二)

GitHub PagesJekyll 靜態網站搭建&#xff08;二&#xff09;GitHub PagesJekyll 靜態網站搭建&#xff08;二內容簡介搭建模板網站部署工作流程GitHub PagesJekyll 靜態網站搭建&#xff08;二 內容簡介 &#x1f6a9; Tech Contents 該文主要涉及Jekyll主題的下載與使用。Gi…

Django 實戰:I18N 國際化與本地化配置、翻譯與切換一步到位

文章目錄一、國際化與本地化介紹定義相關概念二、安裝配置安裝 gettext配置 settings.py三、使用國際化視圖中使用序列化器和模型中使用四、本地化操作創建或更新消息文件消息文件說明編譯消息文件五、項目實戰一、國際化與本地化介紹 定義 國際化和本地化的目標&#xff0c;…

通過國內扣子(Coze)搭建智能體并接入discord機器人

國內的扣子是無法直接授權給discord的&#xff0c;但是用國外的coze的話&#xff0c;大模型調用太貴&#xff0c;如果想要接入國外的平臺&#xff0c;那就需要通過調用API來實現。 1.搭建智能體&#xff08;以工作流模式為例&#xff09; 首先&#xff0c;我們需要在扣子平臺…

【辦公類-107-02】20250719視頻MP4轉gif(削減MB)

背景需求 最近在寫第五屆智慧項目結題(一共3篇)寫的昏天黑地,日以繼夜。 我自己《基于“AI技術”的幼兒園教學資源開發和運用》提到了AI繪畫、AI視頻和AI編程。 為了更好的展示AI編程的狀態,我在WORD里面插入了MP4轉gif的動圖。 【教學類-75-04】20241023世界名畫-《蒙…

一文講清楚React的render優化,包括shouldComponentUpdate、PureComponent和memo

文章目錄一文講清楚React的render優化&#xff0c;包括shouldComponentUpdate、PureComponent和memo1. React的渲染render機制2. shouldComponentUpdate2.1 先上單組件渲染&#xff0c;驗證state變化2.2 上父子組件&#xff0c;驗證props2. PureComponent2.1 單組件驗證state2.…

物聯網iot、mqtt協議與華為云平臺的綜合實踐(萬字0基礎保姆級教程)

本學期的物聯網技術與應用課程&#xff0c;其結課設計內容包含&#xff1a;mqtt、華為云、PyQT5和MySQL等結合使用&#xff0c;完成了從華為云配置產品信息以及轉發規則&#xff0c;到mqtt命令轉發&#xff0c;再到python編寫邏輯代碼實現相關功能&#xff0c;最后用PyQT5實現面…

使用IntelliJ IDEA和Maven搭建SpringBoot集成Fastjson項目

使用IntelliJ IDEA和Maven搭建SpringBoot集成Fastjson項目 下面我將詳細介紹如何在IntelliJ IDEA中使用Maven搭建一個集成Fastjson的SpringBoot項目&#xff0c;包含完整的環境配置和代碼實現。 一、環境準備 軟件要求 IntelliJ IDEA 2021.x或更高版本JDK 1.8或更高版本&#x…

Java從入門到精通!第九天, 重點!(集合(一))

十一、集合1. 為什么要使用集合(1) 數組存在的弊端1) 數組在初始化之后&#xff0c;長度就不能改變&#xff0c;不方便擴展。2) 數組中提供的屬性和方法比較少&#xff0c;不便于進行添加、刪除、修改等操作&#xff0c;并且效率不高&#xff0c;同時無法直接存儲元素的個數。3…

為什么使用時序數據庫

為什么使用時序數據庫&#xff1f; 時序數據庫&#xff08;Time-Series Database, TSDB&#xff09;是專為時間序列數據優化的數據庫&#xff0c;相比傳統關系型數據庫&#xff08;如MySQL&#xff09;或NoSQL數據庫&#xff08;如MongoDB&#xff09;&#xff0c;它在以下方面…

計算機網絡:(十一)多協議標記交換 MPLS

計算機網絡&#xff1a;&#xff08;十一&#xff09;多協議標記交換 MPLS前言一、傳統網絡的問題二、MPLS&#xff1a;給數據包貼個“標簽”三、MPLS的工作流程1. 入站2. 中間3. 出站四、MPLS的能力前言 前面我們講解了計算機網絡中網絡層的相關知識&#xff0c;包括網絡層轉發…

docker run elasticsearch 報錯

谷粒商城 p103 前提條件&#xff1a; 下載鏡像文件 #存儲和檢索數據 docker pull elasticsearch:7.4.2 #可視化檢索數據 docker pull kibana:7.4.2 創建掛載的文件和配置 mkdir -p /mydata/elasticsearch/config mkdir -p /mydata/elasticsearch/data echo "http.h…

巧用Callbre RVE生成DRC HTML report及CTO的使用方法

對于后端版圖人員&#xff0c;在芯片TO前的LV signoff階段&#xff0c;猶如一段漫長而有期待的朝圣之旅&#xff0c;需要耐心&#xff0c;毅力和信心&#xff0c;在龐雜的DRC中找到一條收斂之路。為了讓此路更為清晰收斂&#xff0c;Calibre提供了一套可追溯對比的富文本方式-H…

產品需求文檔(PRD)格式全解析:從 RP 到 Word 的選擇與實踐

產品需求文檔&#xff08;PRD&#xff09;的形式多種多樣&#xff0c;但核心目標始終一致&#xff1a;清晰傳遞產品需求&#xff0c;讓團隊高效協作。不同公司對 PRD 的格式要求可能不同&#xff0c;有的偏愛直接在原型工具中撰寫&#xff0c;有的則習慣用 Word 整理歸檔。本文…

【C++】入門階段

一、初始化C中的初始化指為變量賦予初始值的過程。初始化方式多樣&#xff0c;適用于不同場景。char cha0; char chb{0}; char chc(\0); char chdcha; char che{};注意事項優先使用列表初始化&#xff08;{}&#xff09;&#xff0c;避免窄化轉換風險。在c11中{ }在變量&#x…

tailscale在ubuntu22.04上使用

支持 x86 和 ARM 架構 CPU 的軟件包已提供 32 位和 64 位版本。 添加 Tailscale 的軟件包簽名密鑰及倉庫&#xff1a; curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/noble.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null c…

深入解析Linux文件重定向原理與dup2系統調用

在Linux中&#xff0c;重定向&#xff08;Redirection&#xff09;是一種強大的功能&#xff0c;允許用戶控制命令的輸入來源&#xff08;stdin&#xff09;和輸出目標&#xff08;stdout和stderr&#xff09;。通過重定向&#xff0c;你可以將命令的輸出保存到文件、從文件讀取…

QGIS制作的儀表盤工程

在QGIS的官方資源庫下載了一個QGIS制作的儀表盤工程&#xff0c;感覺非常炫酷&#xff01;分享給大家&#xff01;下面的儀表盤會將選中的道路數及長度&#xff0c;動態顯示在相應的儀表項中&#xff01;下面的儀表盤會將選中的道路數及長度&#xff0c;動態顯示在相應的儀表項…

Python高級數據類型:集合(Set)

集合是Python中一種非常有用的數據結構&#xff0c;它與列表類似但具有獨特的特性。本文將全面介紹集合的所有知識點&#xff0c;從基礎概念到高級用法&#xff0c;幫助初學者徹底掌握集合的使用。1. 集合簡介1.1 什么是集合&#xff1f;集合&#xff08;Set&#xff09;是Pyth…

【Unity編輯器開發GUI.Window】

Unity GUI.Window 筆記 根據官方文檔2021版本的&#xff0c;點擊鏈接跳轉記錄 概述 GUI.Window 是 Unity IMGUI 系統中用于創建彈出窗口的核心方法&#xff0c;具有以下關鍵特性&#xff1a; 浮動窗口&#xff1a;浮于普通 GUI 控件之上焦點控制&#xff1a;可通過點擊獲得焦…