Python+requests實現接口自動化測試框架

為什么要做接口自動化框架

1、業務與配置的分離

2、數據與程序的分離;數據的變更不影響程序

3、有日志功能,實現無人值守

4、自動發送測試報告

5、不懂編程的測試人員也可以進行測試

正常接口測試的流程是什么?

確定接口測試使用的工具----->配置需要的接口參數----->進行測試----->檢查測試結果----->生成測試報告

測試的工具:python+requests

接口測試用例:excel

一、接口框架如下

1、action包:用來存放關鍵字函數

2、config包:用來存放配置文件

3、TestData:用來存放測試數據,excel表

4、Log包:用來存放日志文件

5、utils包:用來存放公共的類

6、運行主程序interface_auto_test.py

7、Readme.txt:告訴團隊組員使用改框架需要注意的地方

二、接口的數據規范設計---Case設計

一個sheet對應數據庫里面一張表

APIsheet存放
編號;從1開始
接口的名稱(APIName);
請求的url(RequestUrl);
請求的方法(RequestMethod);
傳參的方式(paramsType):post/get請求方法不一樣
用例說明(APITestCase)
是否執行(Active)部分接口已測通,下次不用測試,直接把這里設置成N,跳過此接口

post與get的區別

查看post詳情

post請求參數一般是json串,參數放在from表單里面;參數一般不可見,相對來說安全性高些

查看get詳情

get請求參數一般直接放在url里面

2.1注冊接口用例

  • RequestData:請求的數據
  • (開發制定的傳參方式)
  • RelyData:數據依賴
  • ResponseCode:響應code
  • ResponseData:響應數據
  • DataStore:存儲的依賴數據;如果存在數據庫里面,在表里增加一個字段用來存依賴的數據
  • (存儲的方式是編寫接口自動化的人員來設定的存儲方式)
  • CheckPoint:檢查點
  • Active:是否執行
  • Status:執行用例的狀態,方便查看用例是否執行成功
  • ErrorInfo:case運行失敗,失敗的錯誤信息;eg:是也本身的原因還是case設置失敗,還是其他原因

2.2登錄接口用例

RequestData:請求的數據
(開發制定的傳參方式)

RelyData:數據依賴
(存儲的方式是編寫接口自動化的人員來設定的存儲方式)

ResponseCode:響應code

ResponseData:響應數據

DataStore:存儲的依賴數據;如果存在數據庫里面,在表里增加一個字段用來存依賴的數據
(存儲的方式是編寫接口自動化的人員來設定的存儲方式)

CheckPoint:檢查點

Active:是否執行

Status:執行用例的狀態,方便查看用例是否執行成功

ErrorInfo:case運行失敗,失敗的錯誤信息;eg:是也本身的原因還是case設置失敗,還是其他原因

重點說明下RelyData:數據依賴

采取的是字典:key:value來存儲數據格式;
{"request":{"username":"register->1","password":"register->1"},"response":{"code":"register->1"}}

格式化之后:

{"request":{"username":"register->1","password":"register->1"},"response":{"code":"register->1"}
}

三、創建utils包:用來存放公共的類

3.1 ParseExcel.py 操作封裝excel的類(ParseExcel.py)

#encoding=utf-8
import openpyxl
from openpyxl.styles import Border, Side, Font
import timeclass ParseExcel(object):def __init__(self):self.workbook = Noneself.excelFile = Noneself.font = Font(color = None) # 設置字體的顏色# 顏色對應的RGB值self.RGBDict = {'red': 'FFFF3030', 'green': 'FF008B00'}def loadWorkBook(self, excelPathAndName):# 將excel文件加載到內存,并獲取其workbook對象try:self.workbook = openpyxl.load_workbook(excelPathAndName)except Exception as err:raise errself.excelFile = excelPathAndNamereturn self.workbookdef getSheetByName(self, sheetName):# 根據sheet名獲取該sheet對象try:# sheet = self.workbook.get_sheet_by_name(sheetName)sheet = self.workbook[sheetName]return sheetexcept Exception as err:raise errdef getSheetByIndex(self, sheetIndex):# 根據sheet的索引號獲取該sheet對象try:# sheetname = self.workbook.get_sheet_names()[sheetIndex]sheetname = self.workbook.sheetnames[sheetIndex]except Exception as err:raise err# sheet = self.workbook.get_sheet_by_name(sheetname)sheet = self.workbook[sheetname]return sheetdef getRowsNumber(self, sheet):# 獲取sheet中有數據區域的結束行號return sheet.max_rowdef getColsNumber(self, sheet):# 獲取sheet中有數據區域的結束列號return sheet.max_columndef getStartRowNumber(self, sheet):# 獲取sheet中有數據區域的開始的行號return sheet.min_rowdef getStartColNumber(self, sheet):# 獲取sheet中有數據區域的開始的列號return sheet.min_columndef getRow(self, sheet, rowNo):# 獲取sheet中某一行,返回的是這一行所有的數據內容組成的tuple,# 下標從1開始,sheet.rows[1]表示第一行try:rows = []for row in sheet.iter_rows():rows.append(row)return rows[rowNo - 1]except Exception as err:raise errdef getColumn(self, sheet, colNo):# 獲取sheet中某一列,返回的是這一列所有的數據內容組成tuple,# 下標從1開始,sheet.columns[1]表示第一列try:cols = []for col in sheet.iter_cols():cols.append(col)return cols[colNo - 1]except Exception as err:raise errdef getCellOfValue(self, sheet, coordinate = None,rowNo = None, colsNo = None):# 根據單元格所在的位置索引獲取該單元格中的值,下標從1開始,# sheet.cell(row = 1, column = 1).value,# 表示excel中第一行第一列的值if coordinate != None:try:return sheet[coordinate]except Exception as err:raise errelif coordinate is None and rowNo is not None and \colsNo is not None:try:return sheet.cell(row = rowNo, column = colsNo).valueexcept Exception as err:raise errelse:raise Exception("Insufficient Coordinates of cell !")def getCellOfObject(self, sheet, coordinate = None,rowNo = None, colsNo = None):# 獲取某個單元格的對象,可以根據單元格所在位置的數字索引,# 也可以直接根據excel中單元格的編碼及坐標# 如getCellObject(sheet, coordinate = 'A1') or# getCellObject(sheet, rowNo = 1, colsNo = 2)if coordinate != None:try:# return sheet.cell(coordinate = coordinate)return sheet[coordinate]except Exception as err:raise errelif coordinate == None and rowNo is not None and \colsNo is not None:try:return sheet.cell(row = rowNo,column = colsNo)except Exception as err:raise errelse:raise Exception("Insufficient Coordinates of cell !")def writeCell(self, sheet, content, coordinate = None,rowNo = None, colsNo = None, style = None):#根據單元格在excel中的編碼坐標或者數字索引坐標向單元格中寫入數據,# 下標從1開始,參style表示字體的顏色的名字,比如red,greenif coordinate is not None:try:# sheet.cell(coordinate = coordinate).value = contentsheet[coordinate] = contentif style is not None:sheet[coordinate].\font = Font(color = self.RGBDict[style])self.workbook.save(self.excelFile)except Exception as e:raise eelif coordinate == None and rowNo is not None and \colsNo is not None:try:sheet.cell(row = rowNo,column = colsNo).value = contentif style:sheet.cell(row = rowNo,column = colsNo).\font = Font(color = self.RGBDict[style])self.workbook.save(self.excelFile)except Exception as e:raise eelse:raise Exception("Insufficient Coordinates of cell !")def writeCellCurrentTime(self, sheet, coordinate = None,rowNo = None, colsNo = None):# 寫入當前的時間,下標從1開始now = int(time.time())  #顯示為時間戳timeArray = time.localtime(now)currentTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)if coordinate is not None:try:sheet.cell(coordinate = coordinate).value = currentTimeself.workbook.save(self.excelFile)except Exception as e:raise eelif coordinate == None and rowNo is not None \and colsNo is not None:try:sheet.cell(row = rowNo, column = colsNo).value = currentTimeself.workbook.save(self.excelFile)except Exception as e:raise eelse:raise Exception("Insufficient Coordinates of cell !")if __name__ == '__main__':# 測試代碼pe = ParseExcel()pe.loadWorkBook(r'D:\ProgramSourceCode\Python Source Code\WorkSpace\InterfaceFrame2018\inter_test_data.xlsx')sheetObj = pe.getSheetByName(u"API")print("通過名稱獲取sheet對象的名字:", sheetObj.title)# print help(sheetObj.rows)print("通過index序號獲取sheet對象的名字:", pe.getSheetByIndex(0).title)sheet = pe.getSheetByIndex(0)print(type(sheet))print(pe.getRowsNumber(sheet))  #獲取最大行號print(pe.getColsNumber(sheet))  #獲取最大列號rows = pe.getRow(sheet, 1)  #獲取第一行for i in rows:print(i.value)# # 獲取第一行第一列單元格內容# print pe.getCellOfValue(sheet, rowNo = 1, colsNo = 1)# pe.writeCell(sheet, u'我愛祖國', rowNo = 10, colsNo = 10)# pe.writeCellCurrentTime(sheet, rowNo = 10, colsNo = 11)

3.2 封裝get/post請求(HttpClient.py)

import requests
import jsonclass HttpClient(object):def __init__(self):passdef request(self, requestMethod, requestUrl, paramsType,requestData, headers =None, **kwargs):if requestMethod == "post":print("---", requestData, type(requestData))if paramsType == "form":response = self.__post(url = requestUrl, data = json.dumps(eval(requestData)),headers = headers, **kwargs)return responseelif paramsType == "json":response = self.__post(url = requestUrl, json = json.dumps(eval(requestData)),headers = headers, **kwargs)return responseelif requestMethod == "get":request_url = requestUrlif paramsType == "url":request_url = "%s%s" %(requestUrl, requestData)response = self.__get(url = request_url, params = requestData, **kwargs)return responsedef __post(self, url, data = None, json = None, headers=None,**kwargs):print("----")response = requests.post(url=url, data = data, json=json, headers=headers)return responsedef __get(self, url, params = None, **kwargs):response = requests.get(url, params = params, **kwargs)return responseif __name__ == "__main__":hc = HttpClient()res = hc.request("get", "http://39.106.41.11:8080/getBlogContent/", "url",'2')print(res.json())

?3.3 封裝MD5(md5_encrypt)

import hashlibdef md5_encrypt(text):m5 = hashlib.md5()m5.update(text.encode("utf-8"))value = m5.hexdigest()return valueif __name__ == "__main__":print(md5_encrypt("sfwe"))

3.4 封裝Log

import logging
import logging.config
from config.public_data import baseDir# 讀取日志配置文件
logging.config.fileConfig(baseDir + "\config\Logger.conf")
# 選擇一個日志格式
logger = logging.getLogger("example02")#或者example01def debug(message):# 定義dubug級別日志打印方法logger.debug(message)def info(message):# 定義info級別日志打印方法logger.info(message)def warning(message):# 定義warning級別日志打印方法logger.warning(message)

3.5 封裝發送Email類

?import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from ProjVar.var import *import os
import smtplib
from email import encoders
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import formataddrdef send_mail():mail_host="smtp.qq.com"  #設置服務器mail_user="xiangxiang"    #用戶名mail_pass="cmxx"   #口令sender = 'cm2019@126.com'receivers = ['672014873@qq.com',"cm2019@126.com"] # 接收郵件,可設置為你的QQ郵箱或者其他郵箱# 創建一個帶附件的實例message = MIMEMultipart()message['From'] = formataddr(["自動化測試", "cm2019@126.com"])message['To'] = ','.join(receivers)subject = '自動化測試執行報告'message['Subject'] = Header(subject, 'utf-8')message["Accept-Language"]="zh-CN"message["Accept-Charset"]="ISO-8859-1,utf-8,gbk"# 郵件正文內容message.attach(MIMEText('最新執行的自動化測試報告,請參閱附件內容!', 'plain', 'utf-8'))# 構造附件1,傳送測試結果的excel文件att = MIMEBase('application', 'octet-stream')att.set_payload(open(ProjDirPath+"\\testdata\\testdata.xlsx", 'rb').read())att.add_header('Content-Disposition', 'attachment', filename=('gbk', '', "自動化測試報告.xlsx"))encoders.encode_base64(att)message.attach(att)"""# 構造附件2,傳送當前目錄下的 runoob.txt 文件att2 = MIMEText(open('e:\\a.py','rb').read(), 'base64', 'utf-8')att2["Content-Type"] = 'application/octet-stream'att2["Content-Disposition"] = 'attachment; filename="a.py"'message.attach(att2)"""try:smtpObj = smtplib.SMTP(mail_host)smtpObj.login(mail_user, mail_pass)smtpObj.sendmail(sender, receivers, message.as_string())print("郵件發送成功")except smtplib.SMTPException as e:print("Error: 無法發送郵件", e)if __name__ == "__main__":send_mail()
?

四、 創建config包 用來存放公共的參數、配置文件、長時間不變的變量值

創建public_data.p

import os
# 整個項目的根目錄絕對路勁
baseDir = os.path.dirname(os.path.dirname(__file__))# 獲取測試數據文件的絕對路徑
file_path = baseDir + "/TestData/inter_test_data.xlsx"API_apiName = 2
API_requestUrl = 3
API_requestMothod = 4
API_paramsType = 5
API_apiTestCaseFileName = 6
API_active = 7CASE_requestData = 1
CASE_relyData = 2
CASE_responseCode = 3
CASE_responseData = 4
CASE_dataStore = 5
CASE_checkPoint = 6
CASE_active = 7
CASE_status = 8
CASE_errorInfo = 9# 存儲請求參數里面依賴的數據
REQUEST_DATA = {}# 存儲響應對象中的依賴數據
RESPONSE_DATA = {}if __name__=="__main__":print(file_path)print(baseDir)

五、創建TestData目錄,用來存放測試文件

inter_test_data.xlsx

六、創建action包,用來存放關鍵字函數

6.1 解決數據依賴 (GetRely.py)

from config.public_data import REQUEST_DATA, RESPONSE_DATA
from utils.md5_encrypt import md5_encryptREQUEST_DATA = {"用戶注冊":{"1":{"username":"zhangsan", "password":"dfsdf23"},"headers":{"cookie":"asdfwerw"}}}
RESPONSE_DATA = {"用戶注冊":{"1":{"code":"00"}, "headers":{"age":2342}}}class GetRely(object):def __init__(self):pass@classmethoddef get(self, dataSource, relyData, headSource = {}):print(type(dataSource))print(dataSource)data = dataSource.copy()for key, value in relyData.items():if key == "request":#說明應該去REQUEST_DATA中獲取for k, v in value.items():interfaceName, case_idx = v.split("->")val = REQUEST_DATA[interfaceName][case_idx][k]if k == "password":data[k] = md5_encrypt(val)else:data[k] = valelif key == "response":# 應該去RESPONSE_DATA中獲取for k, v in value.items():interfaceName, case_idx = v.split("->")data[k] = RESPONSE_DATA[interfaceName][case_idx][k]elif key == "headers":if headSource:for key, value in value.items():if key == "request":for k, v in value.items():for i in v:headSource[i] = REQUEST_DATA[k]["headers"][i]elif key == "response":for i, val in value.items():for j in val:headSource[j] = RESPONSE_DATA[i]["headers"][j]return "%s" %dataif __name__ == "__main__":s = {"username": "", "password": "","code":""}h = {"cookie":"123", "age":332}rely = {"request": {"username": "用戶注冊->1", "password": "用戶注冊->1"},"response":{"code":"用戶注冊->1"},"headers":{"request":{"用戶注冊":["cookie"]},"response":{"用戶注冊":["age"]}}}print(GetRely.get(s, rely, h))

6.2 解決數據存儲(RelyDataStore.y)

from config.public_data import RESPONSE_DATA, REQUEST_DATAclass RelyDataStore(object):def __init__(self):pass@classmethoddef do(cls, storePoint, apiName, caseId, request_source = {}, response_source = {}, req_headers={}, res_headers = {}):for key, value in storePoint.items():if key == "request":# 說明需要存儲的依賴數據來自請求參數,應該將數據存儲到REQUEST_DATAfor i in value:if i in request_source:val = request_source[i]if apiName not in REQUEST_DATA:# 說明存儲數據的結構還未生成,需要指明數據存儲結構REQUEST_DATA[apiName]={str(caseId): {i: val}}else:#說明存儲數據結構中最外層結構已存在if str(caseId) in REQUEST_DATA[apiName]:REQUEST_DATA[apiName][str(caseId)][i] = valelse:# 說明內層結構不完整,需要指明完整的結構REQUEST_DATA[apiName][str(caseId)] = {i: val}else:print("請求參數中不存在字段" + i)elif key == "response":#說明需要存儲的依賴數據來自接口的響應body,應該將數據存儲到RESPONSE_DATAfor j in value:if j in response_source:val = response_source[j]if apiName not in RESPONSE_DATA:# 說明存儲數據的結構還未生成,需要指明數據存儲結構RESPONSE_DATA[apiName]={str(caseId): {j: val}}else:#說明存儲數據結構中最外層結構已存在if str(caseId) in RESPONSE_DATA[apiName]:RESPONSE_DATA[apiName][str(caseId)][j] = valelse:# 說明內層結構不完整,需要指明完整的結構RESPONSE_DATA[apiName][str(caseId)] = {j: val}else:print("接口的響應body中不存在字段" + j)elif key == "headers":for k, v in value.items():if k == "request":# 說明需要往REQUEST_DATA變量中寫入存儲數據for item in v:if item in req_headers:header = req_headers[item]if "headers" in REQUEST_DATA[apiName]:REQUEST_DATA[apiName]["headers"][item] = headerelse:REQUEST_DATA[apiName]["headers"] = {item: header}elif k == "response":# 說明需要往RESPONSE_DATA變量中寫入存儲數據for it in v:if it in res_headers:header = res_headers[it]if "headers" in RESPONSE_DATA[apiName]:RESPONSE_DATA[apiName]["headers"][it] = headerelse:RESPONSE_DATA[apiName]["headers"] = {item: header}print(REQUEST_DATA)print(RESPONSE_DATA)if __name__ == "__main__":r = {"username": "srwcx01", "password": "wcx123wac1", "email": "wcx@qq.com"}req_h = {"cookie":"csdfw23"}res_h = {"age":597232}s = {"request": ["username", "password"], "response": ["userid"],"headers":{"request":["cookie"],"response":["age"]}}res = {"userid": 12, "code": "00"}RelyDataStore.do(s, "register", 1, r, res, req_headers=req_h, res_headers=res_h)print(REQUEST_DATA)print(RESPONSE_DATA)

6.3 校驗數據結果(CheckResult.py)

import reclass CheckResult(object):def __init__(self):pass@classmethoddef check(self, responseObj, checkPoint):responseBody = responseObj.json()# responseBody = {"code": "", "userid": 12, "id": "12"}errorKey = {}for key, value in checkPoint.items():if key in responseBody:if isinstance(value, (str, int)):# 等值校驗if responseBody[key] != value:errorKey[key] = responseBody[key]elif isinstance(value, dict):sourceData = responseBody[key]if "value" in value:# 模糊匹配校驗regStr = value["value"]rg = re.match(regStr, "%s" %sourceData)if not rg:errorKey[key] = sourceDataelif "type" in value:# 數據類型校驗typeS = value["type"]if typeS == "N":# 說明是整形校驗if not isinstance(sourceData, int):errorKey[key] = sourceDataelse:errorKey[key] = "[%s] not exist" %keyreturn errorKeyif __name__ == "__main__":r = {"code": "00", "userid": 12, "id": 12}c = {"code": "00", "userid": {"type": "N"}, "id": {"value": "\d+"}}print(CheckResult.check(r, c))

6.4 往excel里面寫結果

from config.public_data import *def write_result(wbObj, sheetObj, responseData, errorKey, rowNum):try:# 寫響應bodywbObj.writeCell(sheetObj, content="%s" %responseData,rowNo = rowNum, colsNo=CASE_responseData)# 寫校驗結果狀態及錯誤信息if errorKey:wbObj.writeCell(sheetObj, content="%s" %errorKey,rowNo=rowNum, colsNo=CASE_errorInfo)wbObj.writeCell(sheetObj, content="faild",rowNo=rowNum, colsNo=CASE_status, style="red")else:wbObj.writeCell(sheetObj, content="pass",rowNo=rowNum, colsNo=CASE_status, style="green")except Exception as err:raise err

七、創建Log目錄用來存放日志

八、主函數

#encoding=utf-8
import requests
import json
from action.get_rely import GetRely
from config.public_data import *
from utils.ParseExcel import ParseExcel
from utils.HttpClient import HttpClient
from action.data_store import RelyDataStore
from action.check_result import CheckResult
from action.write_result import write_result
from utils.Log import *def main():parseE = ParseExcel()parseE.loadWorkBook(file_path)sheetObj = parseE.getSheetByName("API")activeList = parseE.getColumn(sheetObj, API_active)for idx, cell in enumerate(activeList[1:], 2):if cell.value == "y":#需要被執行RowObj = parseE.getRow(sheetObj, idx)apiName = RowObj[API_apiName -1].valuerequestUrl = RowObj[API_requestUrl - 1].valuerequestMethod = RowObj[API_requestMothod - 1].valueparamsType = RowObj[API_paramsType - 1].valueapiTestCaseFileName = RowObj[API_apiTestCaseFileName - 1].value# 下一步讀取用例sheet表,準備執行測試用例caseSheetObj = parseE.getSheetByName(apiTestCaseFileName)caseActiveObj = parseE.getColumn(caseSheetObj, CASE_active)for c_idx, col in enumerate(caseActiveObj[1:], 2):if col.value == "y":#需要執行的用例caseRowObj = parseE.getRow(caseSheetObj, c_idx)requestData = caseRowObj[CASE_requestData - 1].valuerelyData = caseRowObj[CASE_relyData - 1].valueresponseCode = caseRowObj[CASE_responseCode - 1].valueresponseData = caseRowObj[CASE_responseData - 1].valuedataStore = caseRowObj[CASE_dataStore -1].valuecheckPoint = caseRowObj[CASE_checkPoint - 1].value#發送接口請求之前需要做一下數據依賴的處理if relyData:logging.info("處理第%s個接口的第%s條用例的數據依賴!")requestData = GetRely.get(eval(requestData), eval(relyData))httpC = HttpClient()response = httpC.request(requestMethod=requestMethod,requestData=requestData,requestUrl=requestUrl,paramsType=paramsType)# 獲取到響應結果后,接下來進行數據依賴存儲邏輯實現if response.status_code == 200:responseData = response.json()# 進行依賴數據存儲if dataStore:RelyDataStore.do(eval(dataStore), apiName, c_idx - 1, eval(requestData), responseData)# 接下來就是校驗結果else:logging.info("接口【%s】的第【%s】條用例,不需要進行依賴數據存儲!" %(apiName, c_idx))if checkPoint:errorKey = CheckResult.check(response, eval(checkPoint))write_result(parseE, caseSheetObj, responseData, errorKey, c_idx)else:logging.info("接口【%s】的第【%s】條用例,執行失敗,接口協議code非200!" %(apiName, c_idx))else:logging.info("第%s個接口的第%s條用例,被忽略執行!" %(idx -1, c_idx-1))else:logging.info("第%s行的接口被忽略執行!" %(idx -1))if __name__=="__main__":main()

框架待完善,請大家多多指教~

同時,在這我為大家準備了一份軟件測試視頻教程(含面試、接口、自動化、性能測試等),就在下方,需要的可以直接去觀看。

【2025最新版】字節大牛講的最全最細的自動化測試全套教程!永久白嫖,拿走不謝,全程干貨無廢話!逼自己15天內學完,從軟件測試基礎到項目實戰一套全通關!

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

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

相關文章

信息學奧賽一本通 1514:【例 2】最大半連通子圖 | 洛谷 P2272 [ZJOI2007] 最大半連通子圖

【題目鏈接】 ybt 1514:【例 2】最大半連通子圖 洛谷 P2272 [ZJOI2007] 最大半連通子圖 【題目考點】 1. 圖論:強連通分量 縮點 2. 圖論:拓撲排序 有向無環圖動規 【解題思路】 對于圖中任意兩頂點u、v,滿足u到v或v到u有路徑…

Android打aar包問題總結

1、moduleA 依賴 moduleB,將moduleA打包成aar時,未包含 moduleB的resources資源; 方法一:將moduleB的資源,手動拷貝一份到moduleA中; 方法二:使用 fat-aar 插件; 2、fat-aar插件使…

【網絡協議】【http】http 簡單介紹

【網絡協議】【http】http 簡單介紹 1 HTTP 頭部 HTTP 是一種請求-響應協議,客戶端向服務器發送請求,服務器返回響應。 1.1 HTTP 狀態碼 狀態碼是服務器返回給客戶端的 三位數字代碼,用于表示請求的執行結果。 狀態碼按照首位數字分類&am…

談談空間復雜度考量,特別是遞歸調用棧空間消耗?

空間復雜度考量是算法設計的核心要素之一,遞歸調用棧的消耗問題在前端領域尤為突出。 以下結合真實開發場景進行深度解析: 一、遞歸調用棧的典型問題 1. 深層次DOM遍歷的陷阱 // 危險操作:遞歸遍歷未知層級的DOM樹 function countDOMNode…

LeetCode算法題(Go語言實現)_16

題目 給定一個二進制數組 nums 和一個整數 k&#xff0c;假設最多可以翻轉 k 個 0 &#xff0c;則返回執行操作后 數組中連續 1 的最大個數 。 一、代碼實現 func longestOnes(nums []int, k int) int {left, zeroCnt, maxLen : 0, 0, 0for right : 0; right < len(nums); …

【數據結構】棧 與【LeetCode】20.有效的括號詳解

目錄 一、棧1、棧的概念及結構2、棧的實現3、初始化棧和銷毀棧4、打印棧的數據5、入棧操作---棧頂6、出棧---棧頂6.1棧是否為空6.2出棧---棧頂 7、取棧頂元素8、獲取棧中有效的元素個數 二、棧的相關練習1、練習2、AC代碼 個人主頁&#xff0c;點這里~ 數據結構專欄&#xff0c…

攻破tensorflow,勇創最佳agent(2)---損失(loss) 準確率(accuracy)問題

實戰播: 怎么判定一個模型好不好,你設置的值對不對? 需要再看幾個值: 例如: model Sequential()for units in model_structure:model.add(Dense(units, activationrelu))model.add(Dropout(train_config.get(dropout_rate, 0.3)))model.add(Dense(1, activationsigmoid)) 他…

pdfh5 pdf

踩坑1&#xff1a; 渲染失敗 &#xff08;1&#xff09;在vue項目中&#xff0c;讀取本地的pdf文件需要放到public下static文件夾中&#xff0c;不能放在別的地方&#xff1b; &#xff08;2&#xff09;引用時&#xff0c;不能使用相對路徑&#xff0c;因為使用public文件下…

6.5 模擬專題:LeetCode 38. 外觀數列

1. 題目鏈接 LeetCode 38. 外觀數列 2. 題目描述 給定一個正整數 n&#xff0c;生成外觀數列的第 n 項。外觀數列的定義如下&#xff1a; 第 1 項為 "1"。第 n 項是對第 n-1 項的描述。例如&#xff0c;第 2 項描述第 1 項&#xff08;"1"&#xff09;為…

什么是具身智能

具身智能&#xff08;Embodied Intelligence&#xff09;是人工智能與機器人學交叉的前沿領域&#xff0c;強調智能體通過身體與環境的動態交互實現自主學習和進化&#xff0c;其核心在于將感知、行動與認知深度融合?。通俗地講&#xff0c;就是機器人或者智能系統在物理環境中…

git命令使用小記(打補丁)

需求&#xff1a;需要從開發分支提取本人提交代碼&#xff0c;然后合并到主分支 一、制作補丁包 mkdir -p patches for commit in $(git log commitA..commitB --author"username" --reverse --prettyformat:"%h"); do …

mapbox基礎,加載popup彈出窗

????? 主頁: gis分享者 ????? 感謝各位大佬 點贊?? 收藏? 留言?? 加關注?! ????? 收錄于專欄:mapbox 從入門到精通 文章目錄 一、??前言1.1 ??mapboxgl.Map 地圖對象1.2 ??mapboxgl.Map style屬性1.3 ??popup 彈出窗 api1.3.1 ??構造函數1.…

C++11--(1)

目錄 1.列表初始化 {}初始化 C98中 C11中 內置置類型和自定義類型 創建對象也適用 std::initializer_list 2.變量類型推導 auto C98 C11 decltype nullptr 3.范圍for循環 4.STL中一些變化 array 1.創建和初始化 2.訪問元素 ?編輯 3.修改操作 4.支持迭代器…

Promise的狀態和方法是什么?

Promise 的狀態和方法 1. Promise 的狀態 一個 Promise 可以處于以下三種狀態之一&#xff1a; - Pending&#xff08;待定&#xff09;&#xff1a;初始狀態&#xff0c;表示異步操作正在進行中&#xff0c;Promise 還沒有被解決或拒絕。 - Fulfilled&#xff08;已完成&…

Windows云服務器支持哪些數據庫管理系統?

Windows云服務器因其良好的兼容性和企業級支持&#xff0c;廣泛用于網站托管、企業管理系統、金融應用、數據分析等場景。在這些應用中&#xff0c;數據庫管理系統(DBMS)起著至關重要的作用。Windows 服務器支持多種數據庫&#xff0c;包括關系型數據庫(SQL)和非關系型數據庫(N…

MongoDB 實際工作中應用場景

博主介紹&#xff1a;?全網粉絲5W&#xff0c;全棧開發工程師&#xff0c;從事多年軟件開發&#xff0c;在大廠呆過。持有軟件中級、六級等證書。可提供微服務項目搭建與畢業項目實戰&#xff0c;博主也曾寫過優秀論文&#xff0c;查重率極低&#xff0c;在這方面有豐富的經驗…

03 相機標定圖像采集

學完本文,您將獲取一下技能: 1:如何提升標定質量,如選擇標定板,標定圖像采集的注意事項, 2:實現標定圖像自動篩選的代碼 3:量產場景如何通過一張圖像來標定相機 為了實現良好的標定效果,以下因素在標定數據采集前必須設置得當。 標定板選擇 標定板尺寸準確材料平…

GitHub美化個人主頁3D圖表顯示配置操作

這個功能主要是用的這個開源倉庫&#xff1a;https://github.com/yoshi389111/github-profile-3d-contrib 想看效果的話&#xff0c;我的個人主頁&#xff1a;https://github.com/Sjj1024 開始操作 1.創建自己的github主頁屬性項目——跟你github用戶名一致即可&#xff0c;…

buu-jarvisoj_fm-好久不見52

格式化字符串漏洞題 x等于4x等于4???????x等于4???????x等于4 可以知道是第11個參數&#xff0c;%11$ 定位到這個位置&#xff0c;然后%n往這個位置寫入4 1.先用pwndbg調試得到偏移量 2.查看獲取x的地址 3.構造ROP鏈&#xff0c;發送連接 from pwn import *# …

AwesomeQt分享3(含源碼)

AwesomeQt 這個項目包含了多個Qt組件的使用示例&#xff0c;旨在展示Qt各種強大功能的實現方式。 源碼分享 github: awesome_Qtgitee: 后續同步 項目進度 QCustomPlot曲線控件示例 支持排序和篩選的列表控件示例 支持排序和篩選的表格控件示例 屬性表示例 Dock窗口示例 自繪…