Python+requests+unittest+excel搭建接口自动化测试框架(超详细)

🍅 视频学习:文末有免费的配套视频可观看

🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快

一、框架结构

工程目录【文末有配套视频和资料免费领取】

代码:基于python2编写

二、Case文件设计

三、基础包 base

3.1 封装get/post请求(runmethon.py)

import requests
import json
class RunMethod:
    def post_main(self,url,data,header=None):
        res = None
        if header !=None:
            res = requests.post(url=url,data=data,headers=header)
        else:
            res = requests.post(url=url,data=data)
        return res.json()
 
    def get_main(self,url,data=None,header=None):
        res = None
        if header !=None:
            res = requests.get(url=url,data=data,headers=header,verify=False)
        else:
            res = requests.get(url=url,data=data,verify=False)
        return res.json()
 
    def run_main(self,method,url,data=None,header=None):
        res = None
        if method == 'Post':
            res = self.post_main(url,data,header)
        else:
            res = self.get_main(url,data,header)
        return json.dumps(res,ensure_ascii=False,sort_keys=True,indent=2)

3.2 封装mock(mock.py)

from mock import mock
#模拟mock 封装
def mock_test(mock_method,request_data,url,method,response_data):
    mock_method = mock.Mock(return_value=response_data)
    res = mock_method(url,method,request_data)
    return res

四、数据操作包 operation_data

4.1 获取excel单元格中的内容(get_data.py)

#coding:utf-8
from tool.operation_excel import OperationExcel
import data_config
from tool.operation_json import OperetionJson
from tool.connect_db import OperationMysql
class GetData:
    def __init__(self):
        self.opera_excel = OperationExcel()
 
    #去获取excel行数,就是case的个数
    def get_case_lines(self):
        return self.opera_excel.get_lines()
 
    #获取是否执行
    def get_is_run(self,row):
        flag = None
        col = int(data_config.get_run())
        run_model = self.opera_excel.get_cell_value(row,col)
        if run_model == 'yes':
            flag = True
        else:
            flag = False
        return flag
 
    #是否携带header
    def is_header(self,row):
        col = int(data_config.get_header())
        header = self.opera_excel.get_cell_value(row,col)
        if header != '':
            return header
        else:
            return None
    #获取请求方式
    def get_request_method(self,row):
        col = int(data_config.get_run_way())
        request_method = self.opera_excel.get_cell_value(row,col)
        return request_method
 
    #获取url
    def get_request_url(self,row):
        col = int(data_config.get_url())
        url = self.opera_excel.get_cell_value(row,col)
        return url
 
    #获取请求数据
    def get_request_data(self,row):
        col = int(data_config.get_data())
        data = self.opera_excel.get_cell_value(row,col)
        if data == '':
            return None
        return data
 
    #通过获取关键字拿到data数据
    def get_data_for_json(self,row):
        opera_json = OperetionJson()
        request_data = opera_json.get_data(self.get_request_data(row))
        return request_data
 
    #获取预期结果
    def get_expcet_data(self,row):
        col = int(data_config.get_expect())
        expect = self.opera_excel.get_cell_value(row,col)
        if expect == '':
            return None
        return expect
 
    #通过sql获取预期结果
    def get_expcet_data_for_mysql(self,row):
        op_mysql = OperationMysql()
        sql = self.get_expcet_data(row)
        res = op_mysql.search_one(sql)
        return res.decode('unicode-escape')
 
    def write_result(self,row,value):
        col = int(data_config.get_result())
        self.opera_excel.write_value(row,col,value)
 
    #获取依赖数据的key
    def get_depend_key(self,row):
        col = int(data_config.get_data_depend())
        depent_key = self.opera_excel.get_cell_value(row,col)
        if depent_key == "":
            return None
        else:
            return depent_key
 
    #判断是否有case依赖
    def is_depend(self,row):
        col = int(data_config.get_case_depend())
        depend_case_id = self.opera_excel.get_cell_value(row,col)
        if depend_case_id == "":
            return None
        else:
            return depend_case_id
 
    #获取数据依赖字段
    def get_depend_field(self,row):
        col = int(data_config.get_field_depend())
        data = self.opera_excel.get_cell_value(row,col)
        if data == "":
            return None
        else:
            return data

4.2 获取excel中每个列(data_config.py)

#coding:utf-8
class global_var:
    #case_id
    Id = '0'
    request_name = '1'
    url = '2'
    run = '3'
    request_way = '4'
    header = '5'
    case_depend = '6'
    data_depend = '7'
    field_depend = '8'
    data = '9'
    expect = '10'
    result = '11'
#获取caseid
def get_id():
    return global_var.Id
 
#获取url
def get_url():
    return global_var.url
 
def get_run():
    return global_var.run
 
def get_run_way():
    return global_var.request_way
 
def get_header():
    return global_var.header
 
def get_case_depend():
    return global_var.case_depend
 
def get_data_depend():
    return global_var.data_depend
 
def get_field_depend():
    return global_var.field_depend
 
def get_data():
    return global_var.data
 
def get_expect():
    return global_var.expect
 
def get_result():
    return global_var.result
 
def get_header_value():
    return global_var.header

4.3 解决数据依赖(dependent.py )

#coding:utf-8
import sys
import json
sys.path.append('C:/Users/lxz/Desktop/InterFace_JIA')
from tool.operation_excel import OperationExcel
from base.runmethod import RunMethod
from operation_data.get_data import GetData
from jsonpath_rw import jsonpath,parse
class DependdentData:
    def __init__(self,case_id):
        self.case_id = case_id
        self.opera_excel = OperationExcel()
        self.data = GetData()
 
    #通过case_id去获取该case_id的整行数据
    def get_case_line_data(self):
        rows_data = self.opera_excel.get_rows_data(self.case_id)
        return rows_data
 
    #执行依赖测试,获取结果
    def run_dependent(self):
        run_method = RunMethod()
        row_num  = self.opera_excel.get_row_num(self.case_id)
        request_data = self.data.get_data_for_json(row_num)
        #header = self.data.is_header(row_num)
        method = self.data.get_request_method(row_num)
        url = self.data.get_request_url(row_num)
        res = run_method.run_main(method,url,request_data)
        return json.loads(res)
 
    #根据依赖的key去获取执行依赖测试case的响应,然后返回
    def get_data_for_key(self,row):
        depend_data = self.data.get_depend_key(row)
        response_data = self.run_dependent()
        json_exe = parse(depend_data)
        madle = json_exe.find(response_data)
        return [math.value for math in madle][0]
 
if __name__ == '__main__':
    order = {
        "data": {
            "_input_charset": "utf-8",
            "body": "京东订单-1710141907182334",
            "it_b_pay": "1d",
            "notify_url": "http://order.imooc.com/pay/notifyalipay",
            "out_trade_no": "1710141907182334",
            "partner": "2088002966755334",
            "payment_type": "1",
            "seller_id": "yangyan01@tcl.com",
            "service": "mobile.securitypay.pay",
            "sign": "kZBV53KuiUf5HIrVLBCcBpWDg%2FnzO%2BtyEnBqgVYwwBtDU66Xk8VQUTbVOqDjrNymCupkVhlI%2BkFZq1jOr8C554KsZ7Gk7orC9dDbQl
                       pr%2BaMmdjO30JBgjqjj4mmM%2Flphy9Xwr0Xrv46uSkDKdlQqLDdGAOP7YwOM2dSLyUQX%2Bo4%3D", 
            "sign_type": "RSA",
            "string": "_input_charset=utf-8&body=京东订单-1710141907182334&it_b_pay=1d&notify_url=http://order.imooc.com/pay/
                         notifyalipay&out_trade_no=1710141907182334&partner=2088002966755334&payment_type=1&seller_id=yangyan01@
                         tcl.com&service=mobile.securitypay.pay&subject=京东订单-1710141907182334&total_fee=299&sign=kZBV53KuiUf5H
                         IrVLBCcBpWDg%2FnzO%2BtyEnBqgVYwwBtDU66Xk8VQUTbVOqDjrNymCupkVhlI%2BkFZq1jOr8C554KsZ7Gk7orC9dDbQlpr%2BaMmdjO30
                         JBgjqjj4mmM%2Flphy9Xwr0Xrv46uSkDKdlQqLDdGAOP7YwOM2dSLyUQX%2Bo4%3D&sign_type=RSA", 
            "subject": "京东订单-1710141907182334",
            "total_fee": 299
            },
            "errorCode": 1000,
            "errorDesc": "成功",
            "status": 1,
            "timestamp": 1507979239100
        }
    res = "data.out_trade_no"
    json_exe = parse(res)
    madle = json_exe.find(order)
    print [math.value for math in madle][0]

五、工具类包 tool

5.1 操作excel (operation_excel.py)

#coding:utf-8
import xlrd
from xlutils.copy import copy
class OperationExcel:
    def __init__(self,file_name=None,sheet_id=None):
        if file_name:
            self.file_name = file_name
            self.sheet_id = sheet_id    
        else:
            self.file_name = '../dataconfig/case1.xls'
            self.sheet_id = 0
        self.data = self.get_data()
 
    #获取sheets的内容
    def get_data(self):
        data = xlrd.open_workbook(self.file_name)
        tables = data.sheets()[self.sheet_id]
        return tables
 
    #获取单元格的行数
    def get_lines(self):
        tables = self.data
        return tables.nrows
 
    #获取某一个单元格的内容
    def get_cell_value(self,row,col):
        return self.data.cell_value(row,col)
 
    #写入数据
    def write_value(self,row,col,value):
        '''
        写入excel数据
        row,col,value
        '''
        read_data = xlrd.open_workbook(self.file_name)
        write_data = copy(read_data)
        sheet_data = write_data.get_sheet(0)
        sheet_data.write(row,col,value)
        write_data.save(self.file_name)
 
    #根据对应的caseid 找到对应行的内容
    def get_rows_data(self,case_id):
        row_num = self.get_row_num(case_id)
        rows_data = self.get_row_values(row_num)
        return rows_data
 
    #根据对应的caseid找到对应的行号
    def get_row_num(self,case_id):
        num = 0
        clols_data = self.get_cols_data()
        for col_data in clols_data:
            if case_id in col_data:
                return num
            num = num+1
    #根据行号,找到该行的内容
    def get_row_values(self,row):
        tables = self.data
        row_data = tables.row_values(row)
        return row_data
 
    #获取某一列的内容
    def get_cols_data(self,col_id=None):
        if col_id != None:
            cols = self.data.col_values(col_id)
        else:
            cols = self.data.col_values(0)
        return cols
 
 
if __name__ == '__main__':
    opers = OperationExcel()
    print opers.get_cell_value(1,2)

5.2判断字符串包含,判断字典是否相等(common_util.py)

#coding:utf-8
import json
class CommonUtil:
    def is_contain(self,str_one,str_two):
        '''
        判断一个字符串是否再另外一个字符串中
        str_one:查找的字符串
        str_two:被查找的字符串
        '''
        flag = None
        if isinstance(str_one,unicode):
            str_one = str_one.encode('unicode-escape').decode('string_escape')
        return cmp(str_one,str_two)
        if str_one in str_two:
            flag = True
        else:
            flag = False
        return flag
 
 
    def is_equal_dict(self,dict_one,dict_two):
        '''
        判断两个字典是否相等
        '''
        if isinstance(dict_one,str):
            dict_one = json.loads(dict_one)
        if isinstance(dict_two,str):
            dict_two = json.loads(dict_two)
        return cmp(dict_one,dict_two)

5.3 操作header(operation_herder.py)

# coding:utf-8
import requests
import json
from operation_json import OperetionJson
 
 
class OperationHeader:
 
    def __init__(self ,response):
        self.response = json.loads(response)
 
    def get_response_url(self):
        '''
        获取登录返回的token的url
        '''
        url = self.response['data']['url'][0]
        return url
 
    def get_cookie(self):
        '''
        获取cookie的jar文件
        '''
        url = self.get_response_url( ) +"&callback=jQuery21008240514814031887_1508666806688&_=1508666806689"
        cookie = requests.get(url).cookies
        return cookie
 
    def write_cookie(self):
        cookie = requests.utils.dict_from_cookiejar(self.get_cookie())
        op_json = OperetionJson()
        op_json.write_data(cookie)
 
if __name__ == '__main__':
 
    url = "http://www.jd.com/passport/user/login"
    data = {
        "username" :"18513199586",
        "password" :"111111",
        "verify" :"",
        "referer" :"https://www.jd.com"
    }
    res = json.dumps(requests.post(url ,data).json())
    op_header = OperationHeader(res)
    op_header.write_cookie()

5.4 操作json文件(operation_json.py)

#coding:utf-8
import json
class OperetionJson:
 
    def __init__(self,file_path=None):
        if file_path  == None:
            self.file_path = '../dataconfig/user.json'
        else:
            self.file_path = file_path
        self.data = self.read_data()
 
    #读取json文件
    def read_data(self):
        with open(self.file_path) as fp:
            data = json.load(fp)
            return data
 
    #根据关键字获取数据
    def get_data(self,id):
        print type(self.data)
        return self.data[id]
 
    #写json
    def write_data(self,data):
        with open('../dataconfig/cookie.json','w') as fp:
            fp.write(json.dumps(data))
 
 
 
if __name__ == '__main__':
    opjson = OperetionJson()
    print opjson.get_data('shop')

5.5 操作数据库(connect_db.py)

 #coding:utf-8
import MySQLdb.cursors
import json
class OperationMysql:
    def __init__(self):
        self.conn = MySQLdb.connect(
            host='localhost',
            port=3306,
            user='root',
            passwd='123456',
            db='le_study',
            charset='utf8',
            cursorclass=MySQLdb.cursors.DictCursor
            )
        self.cur = self.conn.cursor()
 
    #查询一条数据
    def search_one(self,sql):
        self.cur.execute(sql)
        result = self.cur.fetchone()
        result = json.dumps(result)
        return result
 
if __name__ == '__main__':
    op_mysql = OperationMysql()
    res = op_mysql.search_one("select * from web_user where Name='ailiailan'")
    print res

5.6 发送报告邮件(send_email.py)

#coding:utf-8
import smtplib
from email.mime.text import MIMEText
class SendEmail:
    global send_user
    global email_host
    global password
    email_host = "smtp.163.com"
    send_user = "jiaxiaonan666@163.com"
    password = "jia_668"
    def send_mail(self,user_list,sub,content):
        user = "jiaxiaonan"+"<"+send_user+">"
        message = MIMEText(content,_subtype='plain',_charset='utf-8')
        message['Subject'] = sub
        message['From'] = user
        message['To'] = ";".join(user_list)
        server = smtplib.SMTP()
        server.connect(email_host)
        server.login(send_user,password)
        server.sendmail(user,user_list,message.as_string())
        server.close()
 
    def send_main(self,pass_list,fail_list):
        pass_num = float(len(pass_list))
        fail_num = float(len(fail_list))
        count_num = pass_num+fail_num
        #90%
        pass_result = "%.2f%%" %(pass_num/count_num*100)
        fail_result = "%.2f%%" %(fail_num/count_num*100)
 
 
        user_list = ['609037724@qq.com']
        sub = "接口自动化测试报告"
        content = "此次一共运行接口个数为%s个,通过个数为%s个,失败个数为%s,通过率为%s,失败率为%s" %(count_num,pass_num,fail_num,pass_result,fail_result )
        self.send_mail(user_list,sub,content)
 
if __name__ == '__main__':
    sen = SendEmail()
    sen.send_main([1,2,3,4],[2,3,4,5,6,7])

六、主函数

run_test.py

#coding:utf-8
import sys
sys.path.append("C:/Users/lxz/Desktop/InterFace_JIA")
from base.runmethod import RunMethod
from operation_data.get_data import GetData
from tool.common_util import CommonUtil
from operation_data.dependent_data import DependdentData
from tool.send_email import SendEmail
from tool.operation_header import OperationHeader
from tool.operation_json import OperetionJson
class RunTest:
    def __init__(self):
        self.run_method = RunMethod()
        self.data = GetData()
        self.com_util = CommonUtil()
        self.send_mai = SendEmail()
 
    #程序执行的
    def go_on_run(self):
        res = None
        pass_count = []
        fail_count = []
        #10  0,1,2,3
        rows_count = self.data.get_case_lines()
        for i in range(1,rows_count):
            is_run = self.data.get_is_run(i)
            if is_run:
                url = self.data.get_request_url(i)
                method = self.data.get_request_method(i)
                request_data = self.data.get_data_for_json(i)
                expect = self.data.get_expcet_data_for_mysql(i)
                header = self.data.is_header(i)
                depend_case = self.data.is_depend(i)
                if depend_case != None:
                    self.depend_data = DependdentData(depend_case)
                    #获取的依赖响应数据
                    depend_response_data = self.depend_data.get_data_for_key(i)
                    #获取依赖的key
                    depend_key = self.data.get_depend_field(i)
                    request_data[depend_key] = depend_response_data
                if header == 'write':
                    res = self.run_method.run_main(method,url,request_data)
                    op_header = OperationHeader(res)
                    op_header.write_cookie()
 
                elif header == 'yes':
                    op_json = OperetionJson('../dataconfig/cookie.json')
                    cookie = op_json.get_data('apsid')
                    cookies = {
                        'apsid':cookie
                    }
                    res = self.run_method.run_main(method,url,request_data,cookies)
                else:
                    res = self.run_method.run_main(method,url,request_data)
 
                if self.com_util.is_equal_dict(expect,res) == 0:
                    self.data.write_result(i,'pass')
                    pass_count.append(i)
                else:
                    self.data.write_result(i,res)
                    fail_count.append(i)
        self.send_mai.send_main(pass_count,fail_count)
 
    #将执行判断封装
    #def get_cookie_run(self,header):
if __name__ == '__main__':
    run = RunTest()
    run.go_on_run()

七、总结

Python+requests+unittest+excel搭建接口自动化测试框架是一种流行的方法,可以帮助测试人员以有效和可靠的方式管理API测试用例。以下是该框架的一些主要优点和总结:

  • 灵活和易于扩展:Python作为一种灵活的编程语言,可以轻松地扩展和定制测试框架,以满足特定项目或团队的需求。
  • 高效和可维护:使用Python+requests+unittest+excel框架进行API测试可以大大提高测试效率,并减少手动测试所需的时间和成本。测试脚本易于维护和更新。
  • 完整的测试覆盖:通过使用Excel表格来管理测试数据,可以确保所有测试用例都具有完整的测试覆盖,从而检测更多潜在的错误和缺陷。
  • 生成详细的测试报告:该框架可以生成详细的HTML测试报告,包括测试结果、错误信息和性能统计数据等,以便于分析和评估接口质量。
  • 适用于不同的测试场景:无论您是在测试Web应用程序、客户端应用程序还是其他类型的应用程序,都可以使用此框架进行API测试。它适用于各种测试场景,包括功能测试、性能测试和负载测试等。

总之,Python+requests+unittest+excel搭建接口自动化测试框架是一种功能强大且易于使用的API测试方法。通过这个框架,可以轻松管理和运行大量测试用例,并生成有用的测试报告,以便于分析和评估接口质量。

同时,在这我为大家准备了一份软件测试视频教程(含面试、接口、自动化、性能测试等),就在下方,需要的可以直接去观看,也可以直接【点击文末小卡片免费领取资料文档】

花了2万多买的自动化测试全套教程,现在分享给大家,入门到精通,全程干货无废话(软件测试全栈教程))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/474987.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

006_【基础篇】springboot整合Mybatis

SpringBoot 整合 Mybatis 只需要两步&#xff1a; 案例&#xff1a; 创建数据库 在 IDEA 提供的插件的内置的数据库图形化界面(其他图形化界面软件也可以&#xff0c;都一样&#xff09; 中创建以下数据库&#xff1a; create database if not exists mybatis;use mybatis…

principles of network applications网络应用原理

Creating a network app write programs that: ▪ run on (different) end systems ▪ communicate over network ▪ e.g., web server software communicates with browser software application transport network data link physical application transport network data li…

LeetCode每日一题【206. 反转链表】

思路&#xff1a;双指针&#xff0c;一前一后&#xff0c;逐个把指向后面的指针指向前面。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), ne…

面试常问:为什么 Vite 速度比 Webpack 快

前言 最近作者在学习 webpack 相关的知识&#xff0c;之前一直对这个问题不是特别了解&#xff0c;甚至讲不出个123....&#xff0c;这个问题在面试中也是常见的&#xff0c;作者在学习的过程当中总结了以下几点&#xff0c;在这里分享给大家看一下&#xff0c;当然最重要的是…

安全、合规、提质增效,南方某电网公司如何通过代码审计保障能源数字化转型?

​南方某电网公司供电营业区覆盖十几个州市&#xff0c;是所在省域电网运营和交易的主体&#xff0c;也是承担对外供电和培育电力支柱产业的重要企业。近年来该电网公司在数字化转型方面深耕细作&#xff0c;紧跟工业互联网的时代浪潮&#xff0c;打造设备智慧运维数字化场景&a…

Elasticsearch:ES|QL 入门 - Python Notebook

数据丰富在本笔记本中&#xff0c;你将学习 Elasticsearch 查询语言 (ES|QL) 的基础知识。 你将使用官方 Elasticsearch Python 客户端。 你将学习如何&#xff1a; 运行 ES|QL 查询使用处理命令对表格进行排序查询数据链式处理命令计算值计算统计数据访问列创建直方图丰富数…

数据结构从入门到精通——冒泡排序

冒泡排序 前言一、冒泡排序的基本思想二、冒泡排序的特性总结三、冒泡排序的动画演示四、冒泡排序的具体代码test.c 前言 冒泡排序是一种简单的排序算法&#xff0c;通过重复遍历待排序数列&#xff0c;比较相邻元素的大小并交换位置&#xff0c;使得每一轮遍历后最大&#xf…

蓝桥杯 2023 省A 更小的数

主要思路&#xff1a; 输入一个长度为n的字符串&#xff0c;用二维数组dp[i][j]来记录子串[i, j]是否需要反转一次才能满足条件。使用动态规划自底向上地填充dp数组。根据问题的要求&#xff0c;需要考虑字符串的子串中字符的大小关系来判断是否需要反转。最后统计满足条件的子…

小红书,已破!支持无水印批量下载

在我们刷小红书时&#xff0c;经常会遇到自己喜欢的头像/壁纸/背景图图片或各大博主发布的视频教程&#xff0c;想保存下载使用和后续的查看&#xff0c;但保存下载后发现图片或视频右下角保留小红书的水印&#xff0c;很影响使用查看的体验。 所以本期文章最软库给大家分享一…

3D高斯泼溅的崛起

沉浸式媒体领域正在以前所未有的速度发展&#xff0c;其中 3D 高斯溅射成为一项关键突破。 这项技术在广泛的应用中看起来非常有前景&#xff0c;并且可能会彻底改变我们未来创建数字环境以及与数字环境交互的方式。 在本文中&#xff0c;我们将通过与摄影测量和 NeRF 等前辈进…

JAVA_会话

会话技术 1.会话: 一次会话包含多次请求和响应 2.功能: 在一次会话的范围内的多次请求&#xff0c;共享数据 3.方式: 3.1.客户端会话技术 Cookie(甜点) 1.概念: 客户端会话技术,将数据保存到客户端 2.快速入门: 1.创建Cookie对象,绑定数据new Cookie(String name,String v…

3000+人使用,这套人力资源数据分析工具还能这么用

中国科学院自动化研究所&#xff08;以下简称“自动化所”&#xff09;成立于1956年&#xff0c;是中国科学院率先布局成立的“人工智能创新研究院”的总体牵头单位&#xff0c;是中国最早开展智能科学与技术基础理论、关键技术和创新性应用研究的科研机构&#xff0c;也是中国…

G1和ZGC垃圾回收器学习

前言 ​ 随着JDK17的占有率不断升高和SpringBoot3最低支持JDk17&#xff0c;JDK17很大概率会成为大家后续升级的一个选择&#xff0c;而JDK17上最重要的垃圾回收器G1和ZGC&#xff0c;也就显得格外重要。大家提前了解或者学习一下肯定是有用的。 ​ 本篇文章也默认大家了解一…

Python 全栈体系【四阶】(十五)

第五章 深度学习 一、基本理论 1. 深度学习概述 1.1 引入 1.1.1 人工智能划时代事件 2016 年 3 月&#xff0c;Google 公司研发的 AlphaGo 以 4:1 击败世界围棋顶级选手李世石。次年&#xff0c;AlphaGo2.0 对战世界最年轻的围棋四冠王柯洁&#xff0c;以 3:0 击败对方。背后…

PCB板的叠构剖析及实际案例

PCB板可以有不同的层叠结构&#xff0c;具体取决于电路设计的要求和应用的复杂性。 以下是一些常见的PCB板叠构&#xff0c;包括单层、双层和多层PCB&#xff1a; 单层PCB&#xff08;Single-Layer PCB&#xff09;&#xff1a; 基本结构&#xff1a; 单层PCB由一个绝缘性基板组…

sqllab第二十八关通关笔记(附带28a)

知识点&#xff1a; union select 整体过滤 union all select 替换where id(输入)空格 过滤了&#xff0c;使用%09代替 经过不断的测试&#xff0c;发现原始语句为 where id(输入) 构造payload:id1)and%091(1 成功回显出了相关的信息 好&#xff0c;尝试进行错误注入 构造…

理解树的结构-算法通关村

理解树的结构-算法通关村 1.树的结构 树是一个有n个有限节点组成一个具有层次关系的集合&#xff0c;每个节点有0个或者多个子节点&#xff0c;没有父节点的节点称为根节点&#xff0c;也就是说除了根节点以外每个节点都有父节点&#xff0c;并且有且只有一个。树的种类比较多…

如何自定义异常类

如何自定义异常类 为什么要使用自定义异常类&#xff1f; 在 Java 中&#xff0c;自定义异常是指用户根据自己的需求创建的异常类。Java 提供了一些预定义的异常类&#xff0c;如 NullPointerException、ArrayIndexOutOfBoundsException 等&#xff0c;但有时这些预定义的异常…

直播预告!5位大厂测开学长学姐助力你上岸测开

大家好&#xff0c;我是洋子&#xff0c;24届春招补录&25届暑期实习招聘已经进入到白热化阶段&#xff0c;近期收到了很多同学关于求职问题的咨询&#xff0c;所以开一场公益直播来为大家答疑解惑 主题&#xff1a;校招测试开发求职如何准备&职业发展 时间&#xff1…

十二、MySQL 主从复制+高可用+读写分离

目录 一、mysqlkeeplived实现高可用LVS负载均衡 一、什么是高可用 二、为什么要用高可用 三、高可用的作用 四、keeplived 是什么&#xff1f;它用在哪里 五、安装mysql以及配置主从 六、keepalived安装 1、配置 单VIP 实现高可用 master上配置 2、backup上的配置 3、…