Go語言工程實踐之測試與Gin項目實踐

Go 語言并發編程 及 進階與依賴管理_軟工菜雞的博客-CSDN博客

03 測試

回歸測試一般是QA(質量保證)同學手動通過終端回歸一些固定的主流程場景

集成測試是對系統功能維度做測試驗證,通過服務暴露的某個接口,進行自動化測試

單元測試開發階段,開發者對單獨的函數、模塊做功能驗證

層級從上至下,測試成本逐漸減低,而測試覆蓋率確逐步上升,所以單元測試的覆蓋率一定程度上決定著代碼的質量

3.1.0 單元測試

單元測試主要包括:輸入,測試單元,輸出,以及校對

單元的概念比較廣:包括接口,函數,模塊等;用最后的校對來保證代碼的功能與我們的預期相符;

單側一方面可以保證質量,在整體覆蓋率足夠的情況下,一定程度上既保證了新功能本身的正確性,又未破壞原有代碼的正確性。 另一方面可以提升效率,在代碼有bug的情況下,通過編寫單測,可以在一個較短周期內定位和修復問題

3.1.1 單元測試-規則

基本規范,以 _test.go結尾這樣從文件上就很好了區分源碼和測試代碼

以Test開頭,且連接的第一個字母大寫

TestMain的m.run()會跑這個package下的所有單測

3.1.2 單元測試-例子

HelloTom() 由于代碼邏輯的錯誤沒有輸出Tom

接下來進行測試:TestHelloTom()

3.1.3 單元測試-運行

輸出結果錯誤

3.1.4 單元測試-assert

import 了testify/assert 的Equal函數

3.1.5 單元測試-覆蓋率

這是一個判斷是否及格的函數,超過60分,返回true,否則返回false

右邊是對輸入為70 的單元測試,我們執行右邊的單側

通過指定go test [] --cover參數,我們看輸出了 覆蓋率為66.7。

一共三行,我們的單測試執行了2行,所以為66.7

下一步就是提升覆蓋率,我們可以增加一個不及格的測試case,重新執行所有單側,最終覆蓋率為100%。

也就是說,我們通過不斷對各個分支的測試,保證了覆蓋率和完備性。

3.1.6 單元測試-Tips

實際項目中,一般的要求是50%~60% 覆蓋率,而對于資金型服務,覆蓋率可能要求達到80%;

我們做單元測試,測試分支相互獨立,全面覆蓋,則要求函數體足夠小,這樣就比較簡單的提升覆蓋率,也符合函數設計的單一職責。

3.2 單元測試-依賴

工程中復雜的項目,一般會依賴數據庫、緩存等,而我們的單測需要保證穩定性和冪等性

穩定是指相互隔離,能在任何時間,任何環境,運行測試

冪等是指每一次測試運行都應該產生與之前一樣的結果。而要實現這一目的就要用到mock機制

3.3 單元測試-文件處理

下面舉個例子,打開文件讀入 將文件中的第一行字符串中的11替換成00,執行單測,測試通過,而我們的單測需要依賴本地的文件,如果文件被修改或者刪除測試就會fail

為了保證測試case的穩定性,我們對讀取文件函數進行mock,屏蔽對于文件的依賴

3.4 單元測試-Mock

monkey是一個開源的mock測試庫,可以對method,或者實例方法的方法進行mock(打樁)

打樁指的是:用一個函數A 替換函數B,B作為原函數;A作為打樁函數

Mock Patch(原函數,需要打樁的函數) 的作用域在 Runtime;

Unpatch(打樁函數):打樁結束后把原函數卸載掉

monkey主要是在運行時通過 Go 的 unsafe 包,能夠將內存中函數的地址替換為運行時函數的地址,在測試中調用的就是運行時的打樁函數B地址。

下面是一個mock的使用樣例,通過patch對Readfineline進行打樁mock,默認返回line110,這里通defer卸載mock,這樣整個測試函數就擺脫了本地文件的束縛和依賴

3.5 基準測試

Go 語言還提供了基準測試框架,基準測試是指測試一段程序的運行性能及耗費 CPU 的程度

而我們在實際項目開發中,經常會遇到代碼性能瓶頸,為了定位問題經常要對代碼做性能分析,這就用到了基準測試。使用方法類似于單元測試,

3.5.1 基準測試-例子

這里舉一個服務器負載均衡的例子,首先我們有10個服務器列表,每次隨機(rand包)執行select函數隨機選擇一個執行。

3.5.2 基準測試-運行

基準測試以Benchmark開頭,入參是testing.B, 用b中的N值反復遞增循環測試(對一個測試用例的默認測試時間是 1 秒,當測試用例函數返回時還不到 1 秒,那么 testing.B 中的 N 值將按 1、2、5、10、20、50……遞增,并以遞增后的值重新進行用例函數測試

Resttimer重置計時器,我們在reset之前做了init或其他的準備操作,這些操作不應該作為基準測試的范圍

runparallel()函數是多協程并發測試;執行 2個基準測試,發現代碼在并發情況下存在劣化,主要原因是rand為了保證全局的隨機性和并發安全,持有了一把全局鎖

3.5.3 基準測試-優化

GitHub - bytedance/gopkg: Universal Utilities for Go

而為了解決這一隨機函數性能問題,開源了一個高性能隨機數方法fastrand,上面有開源地址;我們這邊再做一下基準測試,性能提升百倍。主要的思路是犧牲了一定的數列的一致性,在大多數場景是適用的,同學在后面遇到隨機的場景可以嘗試用一下。

4 項目實踐

4.0需求背景

大家應該都是從掘金的 社區話題入口報名的,都看到過這個頁面,頁面的功能包括話題詳情,回帖列表,支持回帖,點贊,和回帖回復

我們今天就以此為需求模型,開發一個該頁面交涉及的服務端小功能。

4.1 需求描述

????????????????下面是需求的詳細描述;Ok,如果該功能由同學自己實現,如何去做模型設計,可以拿筆和紙簡單畫一下,然后打開ide,爭取我們一起完成這個實現,后面跟不上也不要著急,代碼已經托管到github,大家可以自行下載查看GitHub - Moonlight-Zhao/go-project-example

4.2 需求用例

我們從用例分析一步步拆解實現,主要涉及的功能點,用戶瀏覽消費,涉及頁面的展示,包括話題內容和回帖的列表,其實從圖中我們應該會抽出2個實體的,而實體的屬性有哪些,他們之間的聯系又如何? 大家想一下,可以先定義一下結構體

4.3 ER 圖

4.4 分層結構

整體分為三層

repository數據層,service邏輯層,controoler視圖層

數據層關聯底層數據模,也就是這里的model,封裝外部數據的增刪改查,我們的數據存儲在本地文件,通過文件操作拉取話題,帖子數據

數據層面向邏輯層,對service層透明,數據層屏蔽下游數據差異,也就是不管下游是文件,還是數據庫,還是微服務等,對service層的接口模型是不變的。

Servcie邏輯層處理核心業務邏輯接收數據層數據 計算打包業務實體entiy,對應我們的需求,就是話題頁面,包括話題和回帖列表,并上送給視圖層;

Controller視圖層負責處理和外部的交互邏輯,以view視圖的形式返回給客戶端,對于我們需求,封裝json格式化的請求結果,api形式訪問就好

4.5 組件工具

下面介紹下開發涉及的基礎組件和工具

首先是gin,高性能開源的go web框架,我們基于gin 搭建web服務器,在課程手冊應該提到了,這里我們只是簡單的使用,主要涉及路由分發,不會涉及其他復雜的概念。

因為我們引入了web框架,所以就涉及go module依賴管理,如前面依賴管理課程內容講解,我們首先通過go mod是初始化go mod管理配置文件,然后go get下載gin依賴,這里顯示用了V1.3.0版本。

有了框架依賴,我們只需要關注業務本身的實現,

從下至上:reposity-->service-->controller,我們一步步實現。希望大家能跟上我的節奏,從0~1 實現這個項目,如果時間問題,大家可以一步步copy一下,主要是走一下開發思路。

4.6 Repository數據層

首先是reposity,我們可以根據之前的er圖先定義struct文件中每行的格式如圖所示

那如何實現QueryTopicById(話題),QueryPostsByParentId(帖子)

4.6 Repository-index

一方面查詢我們可以全掃描遍歷的方式,但是這雖然能達到我們的目的,但是并非高效的方式;

所以這里引出索引的概念,索引就像書的目錄,可以引導我們快速查找定位我們需要的結果;

這里我們map實現內存索引,在服務對外暴露前,利用文件元數據初始化全局內存索引,這樣就可以實現0(1)的時間復雜度查找操作。

下面是具體的實現,首先是os.Open打開文件,基于file 初始化scanner,通過迭代器方式遍歷scanner數據行,轉化為結構體Topic存儲至內存map,這就是初始化話題內存索引

4.6 Repository-查詢

有了內存索引,下一步就是實現查詢操作就比較簡單了

直接根據查詢key獲得map中的value就好了,這里用到了sync.once,主要適用高并發的場景下只執行一次的場景,這里的基于once的實現模式就是我們平常說的單例模式,減少存儲的浪費。

有了topic的查詢代碼,大家可以照貓畫虎 自行實現一下根據話題id查詢回帖列表的查詢方法

func (*PostDao) QueryPostByParentId(parentId int64) ([]*Post, error) {var posts []*Posterr := db.Where("parent_id = ?", parentId).Find(&posts).Errorif err != nil {util.Logger.Error("find posts by parent_id err:" + err.Error())return nil, err}return posts, nil
}

4.7 Service邏輯層

有了reposity層以后,下面我們開始實現service層,首先我們定義servcie層實體PageInfo,包括:Topic和PostList

下面是具體的servcie流程編排 通過err控制流程退出,正常會返回頁面信息,err為nil

func (f *QueryPageInfoFlow) Do() (*PageInfo, error) {if err := f.checkParam(); err != nil {//簡單的id校驗return nil, err}if err := f.prepareInfo(); err != nil {return nil, err}if err := f.packPageInfo(); err != nil {return nil, err}return f.pageInfo, nil
}

關于prepareInfo方法,話題和回帖信息的獲取都依賴topicid,這樣2個流程沒有相互依賴;

這就可以并行執行,提高執行效率。

WaitGroup Add(2);(2個并行的協程);wait等待兩個協程的信息從數據層返回

大家在后期做項目開發中,一定要思考流程是否可以并行,通過壓榨CPU,降低接口耗時,不要一味的串行實現,浪費多核cpu的資源

Paramcheck 和pack這里就不講了,給大家一點時間 編碼 ,copy代碼

4.8 Controller視圖層

這里我們定義一個view對象,通過code msg打包業務狀態信息,用data承載業務實體信息,輸入

4.9 Router

最后是web服務的引擎配置,path映射到具體的controller。通過path變量傳遞話題id

4.10 運行

最后執行go run 本地啟動web服務,通過curl命令請求服務暴露的接,當然平時寫代碼不可能像我講的這么順暢,難免有bug,大家要做好完備的單元測試,快速定位問題,解決問題。

鼠鼠出bug了捏!

好的,以上就是對社區話題頁面需求的整個實現流程,這樣我們從項目拆解,代碼設計落地,最后測試運行就跑通了整個的項目流程,為大家后期實現項目提供了一定的開發思路。當然實際項目較我們實現的需求會復雜很多,不過大家也不必擔心,可以通過大拆小的思路,將大需求拆解為小需求的思路來分析解決,遇到問題,各個擊破,同時做好充分的測試。 課后作業

非常感謝您閱讀到這里,如果這篇文章對您有幫助,希望能留下您的點贊👍 關注💖 收藏 💕評論💬感謝支持!!!

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

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

相關文章

day-21 代碼隨想錄算法訓練營(19)二叉樹part07

530.二叉搜索樹的最小絕對差 思路一:二叉搜索樹的中序遍歷必為升序數組,加入數組后計算相鄰兩個數差值,即可求出最小絕對差 思路二:同樣的思路,中序遍歷,直接使用指針記錄上一個節點,同時更新…

KAFKA第二課之生產者(面試重點)

生產者學習 1.1 生產者消息發送流程 在消息發送的過程中,涉及到了兩個線程——main線程和Sender線程。在main線程中創建了一個雙端隊列RecordAccumulator。main線程將消息發送給RecordAccumulator,Sender線程不斷從RecordAccumulator中拉取消息發送到K…

03-基礎入門-搭建安全拓展

基礎入門-搭建安全拓展 1、涉及的知識點2、常見的問題3、web權限的設置4、演示案例-環境搭建(1)PHPinfo(2)wordpress(3)win7虛擬機上使用iis搭建網站(4)Windows Server 2003配置WEB站…

C#應用處理傳入參數 - 開源研究系列文章

今天介紹關于C#的程序傳入參數的處理例子。 程序的傳入參數應用比較普遍,特別是一個隨操作系統啟動的程序,需要設置程序啟動的時候不顯示主窗體,而是在后臺運行,于是就有了傳入參數問題,比如傳入/h或者/min等等。所以此…

YOLO v8目標跟蹤詳細解讀(二)

上一篇,結合代碼,我們詳細的介紹了YOLOV8目標跟蹤的Pipeline。大家應該對跟蹤的流程有了大致的了解,下面我們將對跟蹤中出現的卡爾曼濾波進行解讀。 1.卡爾曼濾波器介紹 卡爾曼濾波(kalman Filtering)是一種利用線性…

歐拉OS 使用 CentOS 7 yum repo

一、下載CentOS的repo的yum文件 任何基于CentOS的yum的repo 的url是這樣的: 但歐拉OS輸出這個變量為:openEuler 20.03 (LTS-SP3) 那明顯歐拉想要使用這個yum的url找不到這個版本, 所以直接講這個變量替換為 7, Centos 7的7 然后執行&…

wget 詳解

wget 詳解 wget 詳解基本用法:命令參數:遞歸下載:斷點續傳:限速下載:后臺下載: 示例 wget 詳解 wget(Web Get)是一個用于從網絡上下載文件的命令行工具,常用于在 Linux …

從零實戰SLAM-第七課(多視角幾何)

在七月算法報的班,老師講的蠻好。好記性不如爛筆頭,關鍵內容還是記錄一下吧,課程入口,感興趣的同學可以學習一下。 --------------------------------------------------------------------------------------------------------…

整型int溢出引起的crash

線上系統發生了crash&#xff0c;后發現是整型溢出。 1、初始化函數的偽代碼&#xff1a; init_mem(int count, int size){for(int i0; i<count; i)mem_list[i] i*size; # 溢出發生的地方} 2、問題分析&#xff1a; 原有的變量 i、size 為有符號的int類型&#xff0c;i…

設計模式--策略模式

目錄 一.場景 1.1場景 2.2 何時使用 2.3個人理解 二. 業務場景練習 2.1業務: 2.2具體實現 2.3思路 三.總結 3.1策略模式的特點&#xff1a; 3.2策略模式優點 3.3策略模式缺點 一.場景 1.1場景 許多相關的類僅僅是行為有異&#xff0c;也就是說業務代碼需要根據場景不…

Android數字價格變化的動畫效果的簡單實現

原理&#xff1a;使用ValueAnimator屬性動畫類實現&#xff0c;它通過值的改變手動設置對象的屬性值來實現動畫效果。直接貼代碼&#xff1a; public static void doNumberAnim(TextView tvPrice, float startNumber, float endNumber) {ValueAnimator animator ValueAnimato…

C語言中的 RSA加密和解密算法: 深度探索與實現

C語言中的 RSA加密和解密算法: 深度探索與實現 RSA加密算法是一種非對稱加密算法&#xff0c;即公開密鑰加密&#xff0c;私有密鑰解密。在公開密鑰加密和私有密鑰解密的過程中&#xff0c;密鑰是不同的&#xff0c;這是與其他加密算法的主要區別。RSA算法的安全性依賴于大數分…

ssm+mybatis無法給帶有下劃線屬性賦值問題

原因&#xff1a;mybaitis根據配置&#xff0c;將有下劃線的字段名改為了駝峰格式。 具體見&#xff1a;ssmmybatis無法給帶有下劃線屬性賦值問題&#xff0c;無法獲取數據庫帶下劃線的字段值 - 開發者博客 解決方式&#xff1a; 直接將實體類中的下劃線去掉返回值使用resul…

歸并排序 與 計數排序

目錄 1.歸并排序 1.1 遞歸實現歸并排序&#xff1a; 1.2 非遞歸實現歸并排序 1.3 歸并排序的特性總結: 1.4 外部排序 2.計數排序 2.1 操作步驟: 2.2 計數排序的特性總結: 3. 7種常見比較排序比較 1.歸并排序 基本思想: 歸并排序(MERGE-SORT)是建立在歸并操作上的一種…

代理技術在網絡安全、爬蟲和數據隱私中的多重應用

1. Socks5代理&#xff1a;靈活的數據中轉 Socks5代理協議在網絡通信中起著關鍵作用。與其他代理技術不同&#xff0c;Socks5代理不僅支持TCP連接&#xff0c;還能夠處理UDP流量&#xff0c;使其在需要實時數據傳輸的場景中表現尤為出色。通過將請求和響應中轉到代理服務器&am…

redis分布式集群-redis+keepalived+ haproxy

redis分布式集群架構&#xff08;RedisKeepalivedHaproxy&#xff09;至少需要3臺服務器、6個節點&#xff0c;一臺服務器2個節點。 redis分布式集群架構中的每臺服務器都使用六個端口來實現多路復用&#xff0c;最終實現主從熱備、負載均衡、秒級切換的目標。 redis分布式集…

使用Edge和chrom擴展工具(GoFullPage)實現整頁面截圖或生成PDF文件

插件GoFullPage下載&#xff1a;點擊免費下載 如果在瀏覽網頁時&#xff0c;有需要整個頁面截圖或導出PDF文件的需求&#xff0c;這里分享一個Edge瀏覽器的擴展插件&#xff1a;GoFullPage。 這個工具可以一鍵實現頁面從上到下滾動并截取。 一、打開“管理擴展”&#xff08;…

網絡設備(防火墻、路由器、交換機)日志分析監控

外圍網絡設備&#xff08;如防火墻、路由器、交換機等&#xff09;是關鍵組件&#xff0c;因為它們控制進出公司網絡的流量。因此&#xff0c;監視這些設備的活動有助于 IT 管理員解決操作問題&#xff0c;并保護網絡免受攻擊者的攻擊。通過收集和分析這些設備的日志來監控這些…

Python 3 使用Hadoop 3之MapReduce總結

MapReduce 運行原理 MapReduce簡介 MapReduce是一種分布式計算模型&#xff0c;由Google提出&#xff0c;主要用于搜索領域&#xff0c;解決海量數據的計算問題。 MapReduce分成兩個部分&#xff1a;Map&#xff08;映射&#xff09;和Reduce&#xff08;歸納&#xff09;。…

tauri-react:快速開發跨平臺軟件的架子,支持自定義頭部和窗口陰影效果

tauri-react 一個使用 taurireacttsantd 開發跨平臺軟件的模板&#xff0c;支持窗口頭部自定義和窗口陰影&#xff0c;不用再自己做適配了&#xff0c;拿來即用&#xff0c;非常 nice。 開原地址&#xff1a;GitHub - Sjj1024/tauri-react: 一個最基礎的使用tauri和react開發…