網站首頁 編程語言 正文
引言
在經歷過一些嘗試之后,覺得在當下的項目中運用鏈路壓測的能力,不等著其他人了。
鏈路這個詞其實不如路徑通俗易懂,跟產品溝通這個比較有效率。具體的操作路徑,產品會給一份出來,但是這都是基于UI
和產品思維的文檔,跟接口測試區別還是很大的,只能提供參考依據。
需要端上測試協作,有些業務細節還得端上測試同學幫忙補充一下。還需要運維同事幫忙理一下各個接口的請求量比例,這次的比例我是依據靈光一現
寫出來,然后大家一起調整的。
本次由于比較初級,所以這塊文檔就不寫出來了,放一個圖來表達一下這個鏈路做了些什么,PS:我現在很喜歡用圖而不是文字,溝通效率太高了。推薦工具draw.io
,感興趣的可以參考文末的熱文中兩張架構圖中的介紹。
資源庫1.4鏈路壓測方案
這次把登錄剔除了,因為太慢了,對測試結果影響比較大。
場景思路
場景
場景就是老師登錄,首先會請求一個知識點列表,然后通過知識點屬性篩選推薦課程列表,在對課程列表中的數據進行收藏和取消收藏,在獲取自己當前知識點下的課程列表(包含原創和收藏)。
思路
本次依然采取固定線程的壓測模型,本人預估線程200左右,測試用戶600備用,列表頁保證2頁數據。
每個線程綁定一個用戶,然后用戶開始循環鏈路執行步驟,執行一次當做一次Q
。單次Q
包含9次HTTP
接口請求(放棄了Socket
接口,以后有需求再添加Socket
接口到鏈路中),其中3次修改操作,6次查詢操作。
具體的邏輯通過內部靜態類實現,然后多一個K
類,用來存儲每次獲取的知識點屬性,方便調用。由于接口請求方法都是用基礎數據類型和String
作為參數,所以調用時候會顯得有點啰嗦。但無傷大雅,腳本寫出來,本來就是用完就扔到倉庫里面,改天再用再優化。
Demo實現
package?com.okayqa.composer.performance.resource1_4 import?com.alibaba.fastjson.JSON import?com.alibaba.fastjson.JSONObject import?com.funtester.base.bean.AbstractBean import?com.funtester.base.constaint.ThreadLimitTimesCount import?com.funtester.frame.execute.Concurrent import?com.funtester.httpclient.ClientManage import?com.funtester.utils.ArgsUtil import?com.okayqa.composer.base.OkayBase import?com.okayqa.composer.function.Mirro import?com.okayqa.composer.function.OKClass class?Login_collect_uncollect?extends?OkayBase?{ ????public?static?void?main(String[]?args)?{ ????????ClientManage.init(10,?5,?0,?"",?0) ????????def?util?=?new?ArgsUtil(args) ????????def?thread?=?util.getIntOrdefault(0,?30) ????????def?times?=?util.getIntOrdefault(1,?40) ????????def?tasks?=?[] ????????thread.times?{ ????????????tasks?<<?new?FunTester(it,?times) ????????} ????????new?Concurrent(tasks,?"資源庫1.4登錄>查詢>收藏>取消收藏鏈路壓測").start() ????????allOver() ????} ????private?static?class?FunTester?extends?ThreadLimitTimesCount<Integer>?{ ????????OkayBase?base ????????def?mirro ????????def?clazz ????????FunTester(Integer?integer,?int?times)?{ ????????????super(integer,?times,?null) ????????} ????????@Override ????????void?before()?{ ????????????super.before() ????????????base?=?getBase(t) ????????????mirro?=?new?Mirro(base) ????????????clazz?=?new?OKClass(base) ????????} ????????@Override ????????protected?void?doing()?throws?Exception?{ ???????? ????????????def?klist?=?mirro.getKList()</code><code>????????????mirro.getKList() ????????????def?karray?=?klist.getJSONArray("data") ????????????K?ks ????????????karray.each?{ ????????????????JSONObject?parse?=?JSON.parse(JSON.toJSONString(it)) ????????????????if?(ks?==?null)?{ ????????????????????def?level?=?parse.getIntValue("node_level") ????????????????????def?type?=?parse.getIntValue("ktype") ????????????????????def?id?=?parse.getIntValue("id") ????????????????????ks?=?new?K(id,?type,?level) ????????????????} ????????????} ????????????JSONObject?response?=?clazz.recommend(ks.id,?ks.type,?ks.level)</code><code>????????????clazz.recommend(ks.id,?ks.type,?ks.level)????????????clazz.recommend(ks.id,?ks.type,?ks.level) ????????????def?minis?=?[] ????????????int?i?=?0 ????????????response.getJSONArray("data").each?{ ????????????????if?(i++?<?2)?{ ????????????????????JSONObject?parse?=?JSON.parse(JSON.toJSONString(it)) ????????????????????int?value?=?parse.getIntValue("minicourse_id") ????????????????????minis?<<?value ????????????????} ????????????} ????????????clazz.unCollect(random(minis)) ????????????mirro.getMiniCourseListV3(ks.id,?ks.type,?0,?ks.level)????????????mirro.getMiniCourseListV3(ks.id,?ks.type,?0,?ks.level) ????????} ????} ????private?static?class?K?extends?AbstractBean?{ ????????int?id ????????int?type ????????int?level ????????K(int?id,?int?type,?int?level)?{ ????????????this.id?=?id ????????????this.type?=?type ????????????this.level?=?level ????????} ????} }
其中AbstractBean
類是一個抽象類,用于一些bean
的方法封裝,就是為了省事兒。
package?com.funtester.base.bean import?com.alibaba.fastjson.JSON import?com.alibaba.fastjson.JSONObject import?com.funtester.frame.Save import?com.funtester.frame.SourceCode import?org.slf4j.Logger import?org.slf4j.LoggerFactory import?org.springframework.beans.BeanUtils /** ?*?bean的基類 ?*/ abstract?class?AbstractBean?{ ????static?final?Logger?logger?=?LoggerFactory.getLogger(AbstractBean.class) ????/** ?????*?將bean轉化為json,為了進行數據處理和打印 ?????* ?????*?@return ?????*/ ????JSONObject?toJson()?{ ????????JSONObject.parseObject(JSONObject.toJSONString(this)) ????} ????/** ?????*?文本形式保存 ?????*/ ????def?save()?{ ????????Save.saveJson(this.toJson(),?this.getClass().toString()?+?SourceCode.getMark()); ????} ????/** ?????*?控制臺打印,使用WARN記錄,以便查看 ?????*/ ????def?print()?{ ????????logger.warn(this.getClass().toString()?+?":"?+?this.toString()); ????} ????def?initFrom(String?str)?{ ????????JSONObject.parseObject(str,?this.getClass()) ????} ????def?initFrom(Object?str)?{ ????????initFrom(JSON.toJSONString(str)) ????} ????def?copyFrom(AbstractBean?source)?{ ????????BeanUtils.copyProperties(source,?this) ????} ????def?copyTo(AbstractBean?target)?{ ????????BeanUtils.copyProperties(this,?target) ????} ????/** ?????*?這里bean的屬性必需是可以訪問的,不然會返回空json串 ?????*?@return ?????*/ ????@Override ????String?toString()?{ ????????JSONObject.toJSONString(this) ????} ????@Override ????protected?Object?clone()?{ ????????initFrom(this) ????} }
控制臺輸出
~?~~?~~?~~?~~?~~?~~?~~?~~?~~?~?JSON?~?~~?~~?~~?~~?~~?~~?~~?~~?~~?~
>??{
>??①?.?"rt":1665,
>??①?.?"total":1188,
>??①?.?"qps":18.018,
>??①?.?"failRate":0.0,
>??①?.?"threads":30,
>??①?.?"startTime":"2021-02-24?16:57:23",
>??①?.?"endTime":"2021-02-24?16:58:34",
>??①?.?"errorRate":1.01,
>??①?.?"executeTotal":1188,
>??①?.?"mark":"資源庫1.4登錄>查詢>收藏>取消收藏鏈路壓測241657",
>??①?.?"table":"eJzj5VLAD15sbXm2a8LTXZMN9Uyez9z9dO9Uu2fzl75Yv8ju2ZRtL6b32z3tn/ZsWweE83Lyvhfb1z/t6362tZvT2EChJKMoNaWYgA0KvFy8+F0RlFpckJ9XnKoQkpmbaqVQoVucWpSZmKOQV5qro1Cpm5uakpmYR8gOQq5QyM3MU4AYZWVhYqmQW6yTm1hhZWxoaQxkE9RNjA2UgEfTOoBo1JZRW2hmRSsQ0ccmsBW0tgnVQzS1DatVtLMRn3W0sPXRtCYgAlLtQITXWura/mhaMxCRYC+VXUGyv2nhmkfTGoGI0rCgrsseTWsBImLSIZ1dCA8sOjmMXNfCU9ZAupNYV8MdC4106qdA2vkAniAGq6OJ8AlVi6GB99FgSvTU8BU8egaBg6jsO3iWHwSuoZUPB4EzRn046sNRHw68M0Z9OOrDEe5DABkr1eo="
>??}
~?~~?~~?~~?~~?~~?~~?~~?~~?~~?~?JSON?~?~~?~~?~~?~~?~~?~~?~~?~~?~~?~
原文鏈接:https://mp.weixin.qq.com/s/4xHLP-GZwrNu5cFKdfsB6g
相關推薦
- 2022-05-22 docker部署訪問postgres數據庫的實現方法_docker
- 2022-12-13 Flutter?阻止系統鍵盤彈出的優雅方式_Android
- 2022-07-30 SpringBoot的數據校驗(@Validated注解)、關于validation無法導入的問題解
- 2022-05-31 Android實現文件資源管理器雛形_Android
- 2022-06-10 Python語法學習之進程的創建與常用方法詳解_python
- 2022-07-20 虛擬機下的/dev/sda1占用率為100%
- 2022-03-17 Golang動態調用方法小結_Golang
- 2022-12-22 React?Hook?-?自定義Hook的基本使用和案例講解_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支