日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

阶段三-02 用例之间上下文传递

發布時間:2024/3/13 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 阶段三-02 用例之间上下文传递 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

context上下文,需要運用在接口執行里

參考jmeter后置處理器來設計,借用進程的內存空間來儲存上下文

?那么這個上下文變量放哪里呢?怎么才能做到每個用例都可以共享呢?

結合之前的代碼,我們可以放在用例執的時候,沒個接口執行之前。也就是common的perform_case里

admin? CaseApiDef?里加兩字段

per_proc = models.TextField(blank=True, null=True, verbose_name='前置處理')post_proc = models.TextField(blank=True, null=True, verbose_name='后置處理')

定義好了要在內聯表里展示

現在要用后置處理器取uuid的話用戶需要寫一下python腳本

#{case_ctx['uuid'] = parse(reslut['text'])['uuid']}

加上后置處理并傳入case_ctx,順便用日志記錄下。這樣用戶才能去調用??case_ctx['uuid']?

我們再抄下之前python表達式校驗的代碼改一下就可以用了,之后我們再考慮提取復用的問題。

common里重新寫一個:

def eval_expression(input_, result, case_ctx): # 僅先實現后置處理 TODOif not input_:returnm = re.match(r"#\{.+\}", input_)if not m:raise Exception(f'內容格式不支持,請使用#{{}}包含[{input_}]')exp = m.group()if re.search(r"__.+__", input_): # __import__.os 等被過濾掉raise Exception(f'python表達式包含非法字符或操作')# 約定可提供的數據 resultlocal_params = {'result': result,'re': re,'parse': common.parse_json_like,'case_ctx': case_ctx,}try:# 執行evaleval(exp[2:-1], {}, local_params) # eval執行后會返回一個布爾值,[2:-1]做個切片去掉用戶輸入的#{}# 可以不要返回值 所以不用 if not eval_:except Exception as e:raise Exception(f'表達式執行失敗,請先修正后再執行用例。參考【{e}】')

去運行用例,此時會報錯

斷點看下用戶輸入的我們取道了,但是沒寫入。上面代碼最后一行加上,

trace_msg = traceback.format_exc()?拋出詳細信息再看看

?排除后發現我們在執行用戶給的代碼時出錯了。。。

eval和exec

eval() 函數用來執行一個字符串表達式,并返回表達式的值。

?Python eval() 函數 | 菜鳥教程

exec 執行儲存在字符串或文件中的Python語句,相比于 eval,exec可以執行更復雜的 Python 代碼。??exec obj? ;??obj -- 要執行的表達式。

Python exec 內置語句 | 菜鳥教程

上面的代碼eval的時候就保存了,改成exec就能正常執行了。我們接到異常后又再拋出異常,感覺不夠優雅,干脆直接報錯,我們把異常交給調用它的函數來處理

參數傳遞

以上執行后可以發現我們?case_ctx = {}里uuid值了,那用戶要怎么用?我們想要這些字段都能用上

在common里再寫個方法,通過getattr循環取?redis_key ,?auth_username……的值,沒取到就繼續跑,取到了就給他應該默認的方法,方法暫時沒想到

?Python getattr() 函數 | 菜鳥教程

Python setattr() 函數 | 菜鳥教程

def proc_apidef_params(item: CaseApiDef, case_ctx):for attr in ['redis_key', 'auth_username', 'auth_password', 'bearer_token']:val = getattr(item, attr)if not val:continuesetattr(item, attr, '??')

接下來寫??位置的函數:

把用戶輸入的val校驗里面包含#{}的排除掉,如果排除后里面是0就直接返回它本身并結束。

local_params是給用戶調用的

re.sub()是把? #{}里的替換成?new_content ,從用戶輸入的val里找

new_content ()里matched?是前面?re.sub里r"#\{.+\}"匹配到的:<re.Match object; span=(0, 19), match="#{case_ctx['uuid']}">? 我們?讓?s=matched.group()?就可以取全部組了,值就是?#{case_ctx['uuid']}

def proc_params_expression(val, case_ctx):ms = re.findall(r"#\{.+\}", val)if len(ms) == 0:return vallocal_params = {'case_ctx': case_ctx,'re': re,'parse': common.parse_json_like}def new_content(matched):s = matched.group()if re.search(r"__.+__", s): # __import__.os 等被過濾掉raise Exception(f'python表達式包含非法字符或操作[{s}]')return eval(s[2:-1], {}, local_params)return re.sub(r"#\{.+\}", new_content, val)

?以上就可以通過用戶寫的python腳本取到驗證碼了,再校驗是不是數字

之后要寫登錄接口,我們想要把登錄接口傳入case_ctx里的uuid和code,需要用戶在請求體里寫

{"username":"admin", "password":"wjxMh5UdGNAWp93UlFAvrOIGd7xUXYJdjULHVkuntNmRoFtf473yQ5RI+jV9WZ9ROWU0xShcQgZp+unqbWyjNQ==", "code":"#{case_ctx['code']}", "uuid":"#{case_ctx['uuid']}"}

運行下用例,現在我們的首要目的就是去把用戶寫的腳本替換成參數

請求體中的參數替換

經過分析發現在這個階段的請求體是字符串,所以在這里處理是最合適的。

我們跳進 item.get_request_bodies()?里修改一下

def get_request_bodies(self, case_ctx=None):result = {}for p in self.request_bodies.all(): # type: CaseApiDefRequestBodyif self.api.body_type in ('raw-json', 'raw-xml', 'raw-text'):# 讓用戶能用表達式獲取上下文,如果傳入case_ctx就執行表達式;沒有就返回它本身val = u.common.proc_params_expression(p.raw_value, case_ctx) if case_ctx else p.raw_valuereturn valresult.update({p.param_name: p.param_value}) # todoreturn result

在用例里運行獲取test_plt_case_apidef_requestbody?表的queryset,如果傳入了case_ctx就使用參數腳本替換處理。?沒有傳入case_ctx默認返回?原始數據

?request_body = item.get_request_bodies(case_ctx=case_ctx)?傳入case_ctx,再執行下用例。發現替換成功了,但是我們要的是數字,不是字符串。這是被測平臺返回的是“72”

導致我們轉json的時候就會有異常

?我們之前給用戶開放了 'parse': common.parse_json_like? 的方法?它可以把字符串解析成python的數據類型。只要讓用戶在后置處理時使用就可以?把“72”變成72了

回到 獲取驗證碼答案里,后置處理改下?#{case_ctx['code'] = parse(result['values'])}

重新運行用例,成功了

收尾和優化

之前我們設計的傳入case_ctx才能去調用python表達式,如果用戶不傳入只單純使用表達式呢?請求頭、請求參數也需要表達式呢?

def get_request_bodies(self, case_ctx=None):result = {}for p in self.request_bodies.all(): # type: CaseApiDefRequestBodyif self.api.body_type in ('raw-json', 'raw-xml', 'raw-text'):# 讓用戶能用表達式獲取上下文return u.common.proc_param_expression(p.raw_value, case_ctx)param_name = u.common.proc_param_expression(p.param_name, case_ctx)param_value = u.common.proc_param_expression(p.param_value, case_ctx)result.update({param_name: param_value}) # todoreturn result

寫好以后試試

報錯了

?排除后猜測是這里錯誤

控制臺導入這個測試下,報錯發現 1的位置必須是字符串形式,改成 “1”?就正常了

這樣就ok了

登陸成功后我們要獲取ttoken,方便其他接口的校驗

這是就需要用戶寫一下后置處理的腳本了

#{caes_ctx['token']= parse(result['text'])['token'][7]}

caes_ctx中?加入一個token,取的值是接口執行requests返回的result.text,然后找到token鍵,取第七位之后的字符串

這樣就ok了

目前有個問題,現在perform_api只支持bearer

?最后再用json schema校驗獲取用戶列表返回的json格式正常不

{"type": "object","required": ["content"],"properties": {"content": {"type": "array","items": {"type": "object","required": ["id", "username"],"properties": {"id": {"type": "number"},"username": {"type": "string"},"roles": {"type": "array","items": {"type": "object","required": [],"properties": {"id": {"type": "number"},"name": {"type": "string"},"level": {"type": "number"},"dataScope": {"type": "string"}}}},"job": {"type": "object","required": [],"properties": {"id": {"type": "number"},"name": {"type": "string"}}},"dept": {"type": "object","required": [],"properties": {"id": {"type": "number"},"name": {"type": "string"}}},"deptId": {"type": "number"},"createTime": {"type": "number"}}}},"totalElements": {"type": "number"}} }

?

最后看下這個問題,現在是程序可以調用。但是pycharm不能識別過去

?只需要在utils包的ini.py里加上? ?__all__ = ['common', 'http', 'redis_', 'resp']?

需要注意的是,以后包里有其他模塊以后也要寫進去,不然以后?from?utils?import * 的時候就沒有新模塊。一般不建議?import *

總結

以上是生活随笔為你收集整理的阶段三-02 用例之间上下文传递的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。