Pytest测试实战

Pytest测试框架是动态语言Python专用的测试框架,使用起来非常的简单,这主要得易于它的设计,Pytest测试框架具备强大的功能,丰富的第三方插件,以及可扩展性好,可以很好的和unittest测试框架能够结合起来在项目中使用。本文章主要介绍Pytest测试框架中参数化的详细信息。

      参数化的本质是对列表中的对象进行循环,然后把循环的对象进行一一的赋值,它的应用场景主要是基于相同的业务场景,但是需要不同的测试数据来测试从而达到最大化的覆盖更多的业务场景和测试的覆盖率。理解了这样的一个思想之后,我们就以两个数想加作为案例,来演示Pytest测试框架的参数化实际应用,另外一点需要特别说的是在Pytest测试框架中参数化使用的方式是通过装饰器的方式来进行。刚才也说到它的本质是对列表中的对象进行循环和赋值,那么这个对象可以是列表,也可以是元组以及和字典数据类型,见如下的实战案例,把测试的数据分离到不同的对象中(列表,元组,字典),源码如下:

#!/usr/bin/env python
#!coding:utf-8
import pytest


def add(a,b):
return a+b


@pytest.mark.parametrize('a,b,expect',[
[1,1,2],
[2,2,4],
[3,3,6],
[4,4,8],
[5,5,10]
])
def test_add_list(a,b,expect):
assert add(a,b)==expect

@pytest.mark.parametrize('a,b,expect',[
(1,1,2),
(2,2,4),
(3,3,6),
(4,4,8),
(5,5,10)
])
def test_add_tuple(a,b,expect):
assert add(a,b)==expect


@pytest.mark.parametrize('data',[
{'a':1,'b':1,'expect':2},
{'a':5,'b':5,'expect':10}
])
def test_add_dict(data):
assert add(data['a'],data['b'])==data['expect']

if __name__ == '__main__':
pytest.main(["-s","-v","test_one.py"])

执行后的结果信息如下:

在如上的结果信息中,可以看到真正实现测试用例的代码是很少的,而且把参数化使用到的数据分离到不同的数据类型中。

      下面结合API的测试场景来考虑,被测试的API的代码如下:

#!/usr/bin/env python
#!coding:utf-8
from flask import Flask,jsonify
from flask_restful import Api,Resource,reqparse


app=Flask(__name__)
api=Api(app)


class LoginView(Resource):
def get(self):
return {'status':0,'msg':'ok','data':'this is a login page'}

def post(self):
parser=reqparse.RequestParser()
parser.add_argument('username', type=str, required=True, help='用户名不能为空')
parser.add_argument('password',type=str,required=True,help='账户密码不能为空')
parser.add_argument('age',type=int,help='年龄必须为正正数')
parser.add_argument('sex',type=str,help='性别只能是男或者女',choices=['女','男'])
args=parser.parse_args()
return jsonify(args)

api.add_resource(LoginView,'/login',endpoint='login')

if __name__ == '__main__':
app.run(debug=True)

在基于API测试维度的思想,针对该接口测试我们不考虑接口的安全性,高并发以及它的稳定性方面,单纯的只是从功能层面来考虑进行测试,那么需要针对每个参数是否缺少都得需要进行验证,就会涉及到五个测试用例的设计,我们把数据分别分离到主流的文件中,文件的格式主要为JSON,Yaml,Excel和CSV的文件,先来看分离到JSON的文件内容:

{
  "item":
  [
    {
      "request":
      {
        "url": "http://localhost:5000/login",
        "body":
        {
          "password":"admin",
          "sex":"男",
          "age":18
        }
      },
      "response":
      [
        {
          "message":
          {
            "username": "用户名不能为空"
          }
        }
      ]
    },
    {
      "request":
      {
        "url": "http://localhost:5000/login",
        "body":
        {
          "username":"wuya",
          "sex":"男",
          "age":18
        }
      },
      "response":
      [
        {
        "message":
        {
          "password": "账户密码不能为空"
        }
      }
      ]
    },
    {
      "request":
      {
        "url": "http://localhost:5000/login",
        "body":
        {
          "username":"wuya",
          "password":"admin",
          "sex":"asdf",
          "age":18
        }
      },
      "response":
      [
        {
          "message":
          {
            "sex": "性别只能是男或者女"
          }
        }
      ]
    },
    {
      "request":
      {
        "url": "http://localhost:5000/login",
        "body":
        {
          "username":"wuya",
          "password":"admin",
          "sex":"男",
          "age":"rrest"
        }
      },
      "response":
      [
        {
          "message":
          {
            "age": "年龄必须为正正数"
          }
        }
      ]
    },
    {
      "request":
      {
        "url": "http://localhost:5000/login",
        "body":
        {
          "username":"wuya",
          "password":"admin",
          "sex":"男",
          "age":"18"
        }
      },
      "response":
      [
        {
          "age": 18,
          "password": "admin",
          "sex": "男",
          "username": "wuya"
        }
      ]
    }
  ]
}

涉及到的测试代码为:

#!/usr/bin/env python
#!coding:utf-8
import  pytest
import  requests
import  json


def readJson():
   return json.load(open('login.json','r'))['item']

@pytest.mark.parametrize('data',readJson())
def test_json_login(data):
   r=requests.post(
      url=data['request']['url'],
      json=data['request']['body'])
   assert r.json()==data['response'][0]


if __name__ == '__main__':
   pytest.main(["-s","-v","test_json_login.py"])

再来看分离到Yaml文件的数据:

---
#用户名请求为空
"url": "http://localhost:5000/login"
"body": '{
           "password":"admin",
           "sex":"男",
           "age":18
        }'
"expect": '{
              "message": {
                  "username": "用户名不能为空"
              }
          }'
---
#密码参数为空
"url": "http://localhost:5000/login"
"body": '{
           "username":"admin",
           "sex":"男",
           "age":18
        }'
"expect": '{
              "message": {
                  "password": "账户密码不能为空"
              }
          }'
---
#校验性别参数的验证
"url": "http://localhost:5000/login"
"body": '{
           "username":"wuya",
           "password":"admin",
           "sex":"asdf",
           "age":18
         }'
expect: '{
             "message": {
                 "sex": "性别只能是男或者女"
             }
         }'
---
#校验年龄是否是正整数
"url": "http://localhost:5000/login"
"body": '{
           "username":"wuya",
           "password":"admin",
           "sex":"男",
           "age":"rrest"
         }'
"expect": '{
               "message": {
                   "age": "年龄必须为正正数"
               }
           }'
---
#登录成功
"url": "http://localhost:5000/login"
"body": '{
           "username":"wuya",
           "password":"admin",
           "sex":"男",
           "age":"18"
         }'
"expect": '{
               "age": 18,
               "password": "admin",
               "sex": "男",
               "username": "wuya"
           }'

涉及到的测试代码为:

#!/usr/bin/env python
#!coding:utf-8
import  pytest
import  requests
import  yaml


def readYaml():
   with open('login.yaml','r') as f:
      return list(yaml.safe_load_all(f))


@pytest.mark.parametrize('data',readYaml())
def test_login(data):
   r=requests.post(
      url=data['url'],
      json=json.loads(data['body']))
   assert r.json()==json.loads(data['expect'])

分离到CSV的文件内容为:

涉及到的测试代码为:

#!/usr/bin/env python
#!coding:utf-8
import  pytest
import  requests
import  csv


def readCsv():
   data=list()
   with open('login.csv','r') as f:
      reader=csv.reader(f)
      next(reader)
      for item in reader:
         data.append(item)
   return data



@pytest.mark.parametrize('data',readCsv())
def test_csv_login(data):
   r=requests.post(
      url=data[0],
      json=json.loads(data[1]))
   assert r.json()==json.loads(data[2])

最后来看分离到Excel的文件内容:

涉及到的测试代码为:

#!/usr/bin/env python
#!coding:utf-8
import  pytest
import  requests
import  xlrd


def readExcel():
   data=list()
   book=xlrd.open_workbook('login.xls')
   sheet=book.sheet_by_index(0)
   for item in range(1,sheet.nrows):
      data.append(sheet.row_values(item))
   return data



@pytest.mark.parametrize('data',readExcel())
def test_excel_login(data):
   r=requests.post(
      url=data[0],
      json=json.loads(data[1]))
   assert r.json()==json.loads(data[2])
 

其实我们发现套路都是一样的,不管把数据分离到什么样的数据格式下,都得符合它的本质思想,也就是参数化的本质是对列表中的对象进行循环赋值,把握住这样的一个思想就可以了。整合上面的所有代码,完整代码为:

#!/usr/bin/env python
#!coding:utf-8
import  pytest
import  requests
import  json
import  yaml
import  csv
import  xlrd




def readJson():
   return json.load(open('login.json','r'))['item']

def readYaml():
   with open('login.yaml','r') as f:
      return list(yaml.safe_load_all(f))

def readCsv():
   data=list()
   with open('login.csv','r') as f:
      reader=csv.reader(f)
      next(reader)
      for item in reader:
         data.append(item)
   return data


def readExcel():
   data=list()
   book=xlrd.open_workbook('login.xls')
   sheet=book.sheet_by_index(0)
   for item in range(1,sheet.nrows):
      data.append(sheet.row_values(item))
   return data


@pytest.mark.parametrize('data',readJson())
def test_json_login(data):
   r=requests.post(
      url=data['request']['url'],
      json=data['request']['body'])
   assert r.json()==data['response'][0]


@pytest.mark.parametrize('data',readYaml())
def test_yaml_login(data):
   r=requests.post(
      url=data['url'],
      json=json.loads(data['body']))
   assert r.json()==json.loads(data['expect'])

@pytest.mark.parametrize('data',readCsv())
def test_csv_login(data):
   r=requests.post(
      url=data[0],
      json=json.loads(data[1]))
   assert r.json()==json.loads(data[2])


@pytest.mark.parametrize('data',readExcel())
def test_excel_login(data):
   r=requests.post(
      url=data[0],
      json=json.loads(data[1]))
   assert r.json()==json.loads(data[2])

执行后的结果信息为:

     

      Pytest测试框架最强大的功能除了丰富的第三方插件外,还有就是它的Fixture和共享Fixture的conftest.py,下面具体来看被测试的接口代码:

from flask import  Flask,make_response,jsonify,abort,request
from flask_restful import  Api,Resource
from flask_httpauth import  HTTPBasicAuth

from flask import Flask
from flask_jwt import JWT, jwt_required, current_identity
from werkzeug.security import safe_str_cmp

app=Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'super-secret'
api=Api(app=app)
auth=HTTPBasicAuth()

@auth.get_password
def get_password(name):
   if name=='admin':
      return 'admin'
@auth.error_handler
def authoorized():
   return make_response(jsonify({'msg':"请认证"}),403)

books=[
   {'id':1,'author':'wuya','name':'Python接口自动化测试实战','done':True},
   {'id':2,'author':'无涯','name':'Selenium3自动化测试实战','done':False}
]


class User(object):
   def __init__(self, id, username, password):
      self.id = id
      self.username = username
      self.password = password

   def __str__(self):
      return "User(id='%s')" % self.id

users = [
   User(1, 'wuya', 'asd888'),
   User(2, 'admin', 'admin'),
]

username_table = {u.username: u for u in users}
userid_table = {u.id: u for u in users}

def authenticate(username, password):
   user = username_table.get(username, None)
   if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')):
      return user

def identity(payload):
   user_id = payload['identity']
   return userid_table.get(user_id, None)

jwt = JWT(app, authenticate, identity)

class Books(Resource):
   # decorators = [auth.login_required]
   decorators=[jwt_required()]

   def get(self):
      return jsonify({'status':0,'msg':'ok','datas':books})

   def post(self):
      if not request.json:
         return jsonify({'status':1001,'msg':'请求参数不是JSON的数据,请检查,谢谢!'})
      else:
         book = {
            'id': books[-1]['id'] + 1,
            'author': request.json.get('author'),
            'name': request.json.get('name'),
            'done': True
         }
         books.append(book)
         return jsonify({'status':1002,'msg': '添加书籍成功','datas':book}, 201)


class Book(Resource):
   # decorators = [auth.login_required]
   # decorators = [jwt_required()]
   def get(self,book_id):
      book = list(filter(lambda t: t['id'] == book_id, books))
      if len(book) == 0:
         return jsonify({'status': 1003, 'msg': '很抱歉,您查询的书的信息不存在'})
      else:
         return jsonify({'status': 0, 'msg': 'ok', 'datas': book})

   def put(self,book_id):
      book = list(filter(lambda t: t['id'] == book_id, books))
      if len(book) == 0:
         return jsonify({'status': 1003, 'msg': '很抱歉,您查询的书的信息不存在'})
      elif not request.json:
         return jsonify({'status': 1001, 'msg': '请求参数不是JSON的数据,请检查,谢谢!'})
      elif 'author' not in request.json:
         return jsonify({'status': 1004, 'msg': '请求参数author不能为空'})
      elif 'name' not in request.json:
         return jsonify({'status': 1005, 'msg': '请求参数name不能为空'})
      elif 'done' not in request.json:
         return jsonify({'status': 1006, 'msg': '请求参数done不能为空'})
      elif type(request.json['done'])!=bool:
         return jsonify({'status': 1007, 'msg': '请求参数done为bool类型'})
      else:
         book[0]['author'] = request.json.get('author', book[0]['author'])
         book[0]['name'] = request.json.get('name', book[0]['name'])
         book[0]['done'] = request.json.get('done', book[0]['done'])
         return jsonify({'status': 1008, 'msg': '更新书的信息成功', 'datas': book})

   def delete(self,book_id):
      book = list(filter(lambda t: t['id'] == book_id, books))
      if len(book) == 0:
         return jsonify({'status': 1003, 'msg': '很抱歉,您查询的书的信息不存在'})
      else:
         books.remove(book[0])
         return jsonify({'status': 1009, 'msg': '删除书籍成功'})

api.add_resource(Books,'/v1/api/books')
api.add_resource(Book,'/v1/api/book/<int:book_id>')

if __name__ == '__main__':
   app.run(debug=True)

我们通过token的方式,首先需要授权,授权成功后才可以针对书籍这些接口进行操作,如添加删除以及查看所有的书籍信息,那么获取token这部分的代码完全可以放在conftest.py里面,具体源码为:

#!/usr/bin/env python
#!coding:utf-8
import  requests
import  pytest

@pytest.fixture()
def getToken():
   '''获取token'''
   r=requests.post(
      url='http://localhost:5000/auth',
      json={"username":"wuya","password":"asd888"})
   return r.json()['access_token']

Fixture一点需要考虑的是初始化与清理,也就是说在一个完整的测试用例中,都必须都得有初始化与清理的部分,这样才是一个完整的测试用例的。Fixture可以很轻松的来解决这部分,还有一点需要说的是Fixture的函数也可以和返回值整合起来,如添加书籍成功后,把数据ID返回来,下面就以查看书籍为案例,那么查看书籍前提是需要添加书籍,这样可以查看,最后把添加的书籍删除,这样一个测试用例执行完成后才符合它的完整流程,具体测试代码如下:

#!/usr/bin/env python
#!coding:utf-8
import pytest
import  requests

def writeBookID(bookID):
   with open('bookID','w') as f:
      f.write(str(bookID))

@pytest.fixture()
def getBookID():
   with open('bookID','r') as f:
      return  f.read()

def addBook(getToken):
   r=requests.post(
      url='http://localhost:5000/v1/api/books',
      json={"author": "wuya","done": False,"name": "Selenium3自动化测试实战"},
      headers={'Authorization':'JWT {0}'.format(getToken)})
   print('添加书籍:\n',r.json())
   writeBookID(r.json()[0]['datas']['id'])


def delBook(getToken,getBookID):
   r=requests.delete(
      url='http://localhost:5000/v1/api/book/{0}'.format(getBookID),
      headers={'Authorization':'JWT {0}'.format(getToken)})
   print('删除书籍:\n',r.json())

@pytest.fixture()
def init(getToken,getBookID):
   addBook(getToken)
   yield
   delBook(getToken,getBookID)

def test_get_book(init,getToken,getBookID):
   r=requests.get(
      url='http://localhost:5000/v1/api/book/{0}'.format(getBookID),
      headers={'Authorization':'JWT {0}'.format(getToken)})
   print('查看书籍:\n',r.json())

在如上的代码中可以看到,我们刻意了写了init的Fixture函数,就是使用了它的初始化与清理的思想,当然还可以结合内置的Fixture把代码改造为如下的部分:

#!/usr/bin/env python
#!coding:utf-8
import pytest
import  requests
import  allure


@allure.step
def addBook(getToken):
   r=requests.post(
      url='http://localhost:5000/v1/api/books',
      json={"author": "无涯","done": False,"name": "Selenium3自动化测试实战"},
      headers={'Authorization':'JWT {0}'.format(getToken)})
   print('添加书籍:\n',r.json())
   return r.json()[0]['datas']['id']


@allure.step
def delBook(getToken,bookID):
   r=requests.delete(
      url='http://localhost:5000/v1/api/book/{0}'.format(bookID),
      headers={'Authorization':'JWT {0}'.format(getToken)})
   print('删除书籍:\n',r.json())


def test_get_book(getToken,tmpdir):
   f=tmpdir.join('bookid.txt')
   f.write(addBook(getToken))
   r=requests.get(
      url='http://localhost:5000/v1/api/book/{0}'.format(f.read()),
      headers={'Authorization':'JWT {0}'.format(getToken)})
   delBook(getToken=getToken,bookID=f.read())
   print('查看书籍:\n',r.json())

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

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

相关文章

启明云端ESP32-S3模组WT32-S3选型,Flash最大可选16MB,PSRAM最大可选8MB

使用ESP32-S3单芯片&#xff0c;可以完成语音连接屏控三合一功能。接下来给大家推荐一款ESP32-S3模组WT32-S3&#xff0c;Flash 最大可选 16MB,PSRAM 最大可选 8MB。核心芯片是ESP32-S3。 2.4GHz Wi-Fi(802.11b/g/n)Bluetooth 5(LE)模组&#xff0c;内置ESP32-S3系列芯片&#…

分析人工智能在智慧银行服务中的实际应用以及面临的挑战

一、引言 近年来,人工智能(AI)技术快速发展,其在金融领域,特别是智慧银行服务中的应用日益广泛。人工智能以其独特的数据处理能力、预测分析能力以及自动化决策能力,极大地提升了智慧银行的服务效率、降低了运营成本,并优化了客户体验。然而,人工智能在智慧银行服务中…

建模:3dmax

3Dmax 制作模型和动画&#xff08;橘肉&#xff09;&#xff1b; RizomUV 对模型进行展UV&#xff08;橘皮&#xff09;&#xff1b; Substance Painter 纹理手绘&#xff08;给橘皮制定想要的皮肤&#xff09;&#xff1b; 1.基础 1.1可编辑多边形、可编辑样条线 体、面都需要…

霍庭格TruPlasma MF 7100 7050电源现货50KW

霍庭格TruPlasma MF 7100 7050电源现货50KW

力扣HOT100 - 416. 分割等和子集

解题思路&#xff1a; 动态规划 对于当前考虑的元素 nums[i]&#xff0c;如果 dp[ j - nums[ i ] ] 为 true&#xff0c;说明可以用前面的元素构成和为 j -nums[ i ] 的子集&#xff0c;那么在加上当前元素 nums[ i ] 的情况下&#xff0c;就可以构成和为 j 的子集&#xff0…

【MySQL】 查询进阶 | 聚合查询 | 联合查询 | 聚合函数 | 笛卡尔积 | 内连接 | 外链接 | 自连接 | 子查询 | 合并查询

文章目录 查询进阶1.聚合查询1.聚合函数2.group by 子句3.having 2.联合查询笛卡尔积 1.内连接查询许仙同学的成绩查询所有同学的总成绩查询所有同学的每门课程和分数&#xff1a; 2.外连接1.内连接&#xff1a;2.左外连接3.右外链接 3.自连接4.子查询单行子查询多行子查询查询…

CA、ukey、java对接登录

Ukey登录 随着互联网技术的发展&#xff0c;越来越多的应用需要用户进行登录&#xff0c;以验证其身份和权限。为了增强安全性&#xff0c;许多应用选择使用硬件设备来存储和管理用户的身份信息。Ukey&#xff08;也称为USB Key&#xff09;是一种常见的硬件设备&#xff0c;用…

【极简】docker常用操作

镜像images是静态的 容器container是动态的&#xff0c;是基于镜像的&#xff0c;类似于一个进程。 查看docker images&#xff1a; docker images 或者docker image ls 查看docker container情况&#xff1a;docker ps -a&#xff0c;-a意思是--all 运行一个container: doc…

高效水深度除六价铬工艺的技术研究与应用

关键词&#xff1a;六价铬&#xff1b;水处理&#xff1b;离子交换&#xff1b;环境保护&#xff1b;技术创新​ 随着工业化进程的加速&#xff0c;重金属污染尤其是六价铬的排放问题日益严重。六价铬是一种高度有害的污染物&#xff0c;广泛存在于电镀、染料制造、皮革加工等…

JUnit5测试用例

1.用Test注解表示为测试方法 2.使用DisplayName定义别名 3.使用Assertions类的断言方法 使用断言&#xff0c;可以判断方法的实际执行结果和预期结果是否一致 assertEqualsassertTureassertNotNullassertAllassertThrows 下图是预期与实际不同时报错图 4.使用BeforeEach注解&…

【原创】java+springboot+mysql企业邮件管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

uniapp微信小程序使用vscode代替HBuilderX开发uniapp微信小程序并且vscode改动代码微信开发者工具能实时更新

前言 最近公司开发新的小程序项目&#xff0c;经调研综合所有人员考虑&#xff0c;用uni-app Vue3tsvite技术栈开发&#xff1b;而官方推荐使用HBuilderX开发&#xff0c;而考虑到目前公司所有前端人员对VsCode更熟悉&#xff0c;故此总结了一下uniapp项目使用vscode代替HBuild…

vue3 + antd-vue@4 a-table单元格合并,rowSpan(行合并),colSpan(列合并)详解, 表头合并详解, 表头自定义详解

一、解释 1、rowSpan 1&#xff09;、行合并 2&#xff09;、当为0时&#xff1a;去掉边框 3&#xff09;、当为1时&#xff1a;不合并 4&#xff09;、大于1的x时&#xff1a;包含当前单元格行合并x个单元格 2、colSpan 1&#xff09;、列合并 2&#xff09;、当为0时&#xf…

C++ 将字符串解析为argc、argv

文章目录 前言一、如何实现&#xff1f;1、实现split2、split双引号3、奇数下标元素加入结果4、偶数下标元素split空格 二、完整代码三、使用示例1、解析命令行2、构造argc、argv 总结 前言 一般开启子进程的时候&#xff0c;需要传参数&#xff0c;通常直接传输命令行字符串&…

SQL使用Groupby分组后,选择每个分组某个值最大的那一行

思路是&#xff1a; 先定位分组后某个值最大的值是多少根据值去全表匹配&#xff0c;得到对应的行 比如有个表&#xff1a; SELECT * FROM my_table按照sku_id分组后&#xff0c;选择record_date最大的那一行的全部值&#xff0c;先分组&#xff1a; SELECT sku_id,max(rec…

党建管理系统源码 搭建智慧党建小程序+支持在线缴费、考试、学习 功能强大

随着信息技术的飞速发展&#xff0c;党建工作也迎来了数字化、智能化的新时代。为了提升党建工作的效率&#xff0c;优化党员参与体验&#xff0c;基于党建管理系统源码的智慧党建小程序非常好用。分享一款春哥智慧党建小程序源码&#xff0c;该小程序集成了在线缴费、考试、学…

什么是蜜罐,在当前网络安全形势下,蜜罐能提供哪些帮助

在当前的互联网时代&#xff0c;网络安全威胁日益严峻&#xff0c;攻击手段层出不穷。为了应对这些威胁&#xff0c;网络安全专家们不断探索新的防御手段&#xff0c;在过去的几年里&#xff0c;一种更加积极主动的网络安全方法正在兴起。蜜罐技术便是这样一种备受瞩目的主动防…

echers配置项:折线图,折现的颜色修改

如上图所示&#xff1a;红框内的折现颜色修改&#xff0c;并隐藏默认的点 series: [{data: [1, 230, 224, 218, 135, 147, 760,1500,1200,2500,2000],type: line,lineStyle: {color: #00DBFE // 折现颜色},symbol:none, // 不显示点smooth: true, // 折现角度&#xff1a;圆滑…

ARM架构安全特性之防御执行技术

安全之安全(security)博客目录导读 目录 1、侧信道攻击威胁 2、推测屏障Speculation Barriers 3、栈溢出攻击威胁 4、指针认证PAC 5、分支目标识别BTI 6、内存安全违规威胁 7、内存标记扩展MTE 8、加强数据保护 9、特权不可访问&#xff08;Privileged Access Never …

Unity Mirror 从入门到入神(一)

Mirror从入门到成神 文章目录 Mirror从入门到成神简介NetworkClientRegisterPrefabConnect (string address)Disconnect ()activeactiveHost NetworkServerSpawn 简介 Mirror是一个unity网络同步框架&#xff0c;基于MonoBehaviour生命周期的回调的基础上进行数值的同步&#…