python+requests+pytest+allure自动化框架

1.核心库

requests request请求

openpyxl excel文件操作

loggin 日志

smtplib 发送邮件

configparser

unittest.mock mock服务

2.目录结构

base

utils

testDatas

conf

testCases

testReport

logs

其他

图片

2.1base

base_path.py 存放绝对路径,dos命令或Jenkins执行时,防止报错

base_requests.py 封装requests,根据method选择不同的方法执行脚本,同时处理请求异常

2.1.1 base_path.py

import os

# 项目根路径
_root_path = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]

# 报告路径
report_path = os.path.join(_root_path, 'testReport', 'report.html')

# 日志路径
log_path = os.path.join(_root_path, 'logs/')

# 配置文件路径
conf_path = os.path.join(_root_path, 'conf', 'auto_test.conf')

# 测试数据路径
testdatas_path = os.path.join(_root_path, 'testDatas')

# allure 相关配置
_result_path = os.path.join(_root_path, 'testReport', 'result')
_allure_html_path = os.path.join(_root_path, 'testReport', 'allure_html')
allure_command = 'allure generate {} -o {} --clean'.format(_result_path, _allure_html_path)

2.1.2 base_requests.py

import json
import allure
import urllib3
import requests
import warnings
from bs4 import BeautifulSoup
from base.base_path import *
from requests.adapters import HTTPAdapter
from utils.handle_logger import logger
from utils.handle_config import handle_config as hc


class BaseRequests:

    def __init__(self, case, proxies=None, headers=None, cookies=None, timeout=15, max_retries=3):
        '''
        :param case: 测试用例
        :param proxies: The result is displayed in fiddler:
        {"http": "http://127.0.0.1:8888", "https": "https://127.0.0.1:8888"}
        :param headers: 请求头
        :param cookies: cookies
        :param timeout: 请求默认超时时间15s
        :param max_retries: 请求超时后默认重试3次
        '''
        self.case = case
        self.proxies = proxies
        self.headers = headers
        self.cookies = cookies
        self.timeout = timeout
        self.max_retries = max_retries
        self.base_url = hc.operation_config(conf_path, 'BASEURL', 'base_url')

    def get_response(self):
        '''获取请求结果'''
        response = self._run_main()
        return response

    def _run_main(self):
        '''发送请求'''
        method = self.case['method']
        url = self.base_url + self.case['url']
        if self.case['parameter']:
            data = eval(self.case['parameter'])
        else:
            data = None

        s = requests.session()
        s.mount('http://', HTTPAdapter(max_retries=self.max_retries))
        s.mount('https://', HTTPAdapter(max_retries=self.max_retries))
        urllib3.disable_warnings()  # 忽略浏览器认证(https认证)警告
        warnings.simplefilter('ignore', ResourceWarning)    # 忽略 ResourceWarning警告

        res=''
        if method.upper() == 'POST':
            try:
                res = s.request(method='post', url=url, data=data, verify=False, proxies=self.proxies, headers=self.headers, cookies=self.cookies, timeout=self.timeout)
            except Exception as e:
                logger.error('POST请求出错,错误信息为:{0}'.format(e))

        elif method.upper() == 'GET':
            try:
                res = s.request(method='get', url=url, params=data, verify=False,proxies=self.proxies, headers=self.headers, cookies=self.cookies, timeout=self.timeout)
            except Exception as e:
                    logger.error('GET请求出错,错误信息为:{0}'.format(e))
        else:
            raise ValueError('method方法为get和post')
        logger.info(f'请求方法:{method},请求路径:{url}, 请求参数:{data}, 请求头:{self.headers}, cookies:{self.cookies}')

        # with allure.step('接口请求信息:'):
        #     allure.attach(f'请求方法:{method},请求路径:{url}, 请求参数:{data}, 请求头:{headers}')

        # 拓展:是否需要做全量契约验证?响应结果是不同类型时,如何处理响应?
        return res


if __name__ == '__main__':
    # case = {'method': 'get', 'url': '/article/top/json', 'parameter': ''}
    case = {'method': 'post', 'url': '/user/login', 'parameter': '{"username": "xbc", "password": "123456"}'}
    response = BaseRequests(case).get_response()
    print(response.json())

2.2 utils

(只取核心部分)

handle_excel.py

excel的操作,框架要求,最终读取的数据需要保存列表嵌套字典的格式[{},{}]
其他操作
handle_sendEmail.py

python发送邮件使用smtp协议,接收邮件使用pop3
需要开启pop3服务功能,这里的password为授权码,启用服务自行百度
handle_logger.py 日志处理

handle_config.py
配置文件处理,这里只将域名可配置化,切换环境时改域名即可

handle_allure.py
allure生成的报告需要调用命令行再打开,这里直接封装命令

handle_cookies.py(略)
在git中补充,处理cookiesJar对象

handle_mock.py(略)
在git中补充,框架未使用到,但是也封装成了方法

param_replace(略)

将常用的参数化操作封装成类

2.2.1 handle_excel.py

import openpyxl
from base.base_path import *

class HandleExcel:
    def __init__(self, file_name=None, sheet_name=None):
        '''
        没有传路径时,默认使用 wanadriod接口测试用例.xlsx 文件
        :param file_name:  用例文件
        :param sheet_name: 表单名
        '''
        if file_name:
            self.file_path = os.path.join(testdatas_path, file_name)
            self.sheet_name = sheet_name
        else:
            self.file_path = os.path.join(testdatas_path, 'wanadriod接口测试用例.xlsx')
            self.sheet_name = 'case'
        # 创建工作簿,定位表单
        self.wb = openpyxl.load_workbook(self.file_path)
        self.sheet = self.wb[self.sheet_name]
        # 列总数,行总数
        self.ncols = self.sheet.max_column
        self.nrows = self.sheet.max_row

    def cell_value(self, row=1, column=1):
        '''获取表中数据,默认取出第一行第一列的值'''
        return self.sheet.cell(row, column).value

    def _get_title(self):
        '''私有函数, 返回表头列表'''
        title = []
        for column in range(1, self.ncols+1):
            title.append(self.cell_value(1, column))
        return title

    def get_excel_data(self):
        '''
        :return: 返回字典套列表的方式 [{title_url:value1, title_method:value1}, {title_url:value2, title_method:value2}...]
        '''
        finally_data = []
        for row in range(2, self.nrows+1):
            result_dict = {}
            for column in range(1, self.ncols+1):
                result_dict[self._get_title()[column-1]] = self.cell_value(row, column)
            finally_data.append(result_dict)
        return finally_data

    def get_pytestParametrizeData(self):
        '''
        选用这种参数方式,需要使用数据格式 列表套列表 @pytest.mark.parametrize('', [[], []]), 如 @pytest.mark.parametrize(*get_pytestParametrizeData)
        将 finally_data 中的 title 取出,以字符串形式保存,每个title用逗号(,)隔开
        将 finally_data 中的 value 取出,每行数据保存在一个列表,再集合在一个大列表内
        :return: title, data
        '''
        finally_data = self.get_excel_data()
        data = []
        title = ''
        for i in finally_data:
            value_list = []
            key_list = []
            for key, value in i.items():
                value_list.append(value)
                key_list.append(key)
            title = ','.join(key_list)
            data.append(value_list)
        return title, data

    def rewrite_value(self, new_value, case_id, title):
        '''写入excel,存储使用过的数据(参数化后的数据)'''
        row = self.get_row(case_id)
        column = self.get_column(title)
        self.sheet.cell(row, column).value = new_value
        self.wb.save(self.file_path)

    def get_row(self, case_id):
        '''通过执行的 case_id 获取当前的行号'''
        for row in range(1, self.nrows+1):
            if self.cell_value(row, 1) == case_id:
                return int(row)

    def get_column(self, title):
        '''通过表头给定字段,获取表头所在列'''
        for column in range(1, self.ncols+1):
            if self.cell_value(1, column) == title:
                return int(column)


if __name__ == '__main__':
    r = HandleExcel()
    print(r.get_excel_data())

2.2.2 handle_sendEmail.py

import smtplib
from utils.handle_logger import logger
from email.mime.text import MIMEText    # 专门发送正文邮件
from email.mime.multipart import MIMEMultipart  # 发送正文、附件等
from email.mime.application import MIMEApplication  # 发送附件

class HandleSendEmail:

    def __init__(self, part_text, attachment_list, password, user_list, subject='interface_autoTestReport', smtp_server='smtp.163.com', from_user='hu_chunpu@163.com', filename='unit_test_report.html'):
        '''
        :param part_text: 正文
        :param attachment_list: 附件列表
        :param password: 邮箱服务器第三方密码
        :param user_list: 收件人列表
        :param subject: 主题
        :param smtp_server: 邮箱服务器
        :param from_user: 发件人
        :param filename: 附件名称
        '''
        self.subject = subject
        self.attachment_list = attachment_list
        self.password = password
        self.user_list = ';'.join(user_list)    # 多个收件人
        self.part_text = part_text
        self.smtp_server = smtp_server
        self.from_user = from_user
        self.filename = filename

    def _part(self):
        '''构建邮件内容'''
        # 1) 构造邮件集合体:
        msg = MIMEMultipart()
        msg['Subject'] = self.subject
        msg['From'] = self.from_user
        msg['To'] = self.user_list

        # 2) 构造邮件正文:
        text = MIMEText(self.part_text)
        msg.attach(text)  # 把正文加到邮件体里面

        # 3) 构造邮件附件:
        for item in self.attachment_list:
            with open(item, 'rb+') as file:
                attachment = MIMEApplication(file.read())
            # 给附件命名:
            attachment.add_header('Content-Disposition', 'attachment', filename=item)
            msg.attach(attachment)

        # 4) 得到完整的邮件内容:
        full_text = msg.as_string()
        return full_text

    def send_email(self):
        '''发送邮件'''
        # qq邮箱必须加上SSL
        if self.smtp_server == 'smtp.qq.com':
            smtp = smtplib.SMTP_SSL(self.smtp_server)
        else:
            smtp = smtplib.SMTP(self.smtp_server)
        # 登录服务器:.login(user=email_address,password=第三方授权码)
        smtp.login(self.from_user, self.password)
        logger.info('--------邮件发送中--------')
        try:
            logger.info('--------邮件发送成功--------')
            smtp.sendmail(self.from_user, self.user_list, self._part())
        except Exception as e:
            logger.error('发送邮件出错,错误信息为:{0}'.format(e))
        else:
            smtp.close()    # 关闭连接

if __name__ == '__main__':
    from base.base_path import *
    part_text = '附件为自动化测试报告,框架使用了pytest+allure'
    attachment_list = [report_path]
    password = ''
    user_list = ['']
    HandleSendEmail(part_text, attachment_list, password, user_list).send_email()

2.2.3 handle_logger.py

import sys
import logging
from time import strftime
from base.base_path import *

class Logger:

    def __init__(self):
        # 日志格式
    custom_format = '%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s: %(message)s'
        # 日期格式
        date_format = '%a, %d %b %Y %H:%M:%S'

        self._logger = logging.getLogger()  # 实例化
        self.filename = '{0}{1}.log'.format(log_path, strftime("%Y-%m-%d")) # 日志文件名
        self.formatter = logging.Formatter(fmt=custom_format, datefmt=date_format)
        self._logger.addHandler(self._get_file_handler(self.filename))
        self._logger.addHandler(self._get_console_handler())
        self._logger.setLevel(logging.INFO)  # 默认等级

    def _get_file_handler(self, filename):
        '''输出到日志文件'''
        filehandler = logging.FileHandler(filename, encoding="utf-8")
        filehandler.setFormatter(self.formatter)
        return filehandler

    def _get_console_handler(self):
        '''输出到控制台'''
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(self.formatter)
        return console_handler

    @property
    def logger(self):
        return self._logger

'''
日志级别:
critical    严重错误,会导致程序退出
error        可控范围内的错误
warning        警告信息
info        提示信息
debug        调试程序时详细输出的记录
'''
# 实例
logger = Logger().logger


if __name__ == '__main__':
    import datetime
    logger.info(u"{}:开始XXX操作".format(datetime.datetime.now()))

2.2.4 handle_config.py

import configparser

# 配置文件类
class HandleConfig:
    def operation_config(self, conf_file, section, option):
        cf = configparser.ConfigParser()    # 实例化
        cf.read(conf_file)
        value = cf.get(section, option)    # 定位
        return value


handle_config = HandleConfig()
if __name__ == '__main__':
    from base.base_path import *
    base_url = handle_config.operation_config(conf_path, 'BASEURL', 'base_url')
    print(base_url)

2.2.5 handle_allure.py

import subprocess
from base.base_path import *

class HandleAllure(object):

    def execute_command(self):
        subprocess.call(allure_command, shell=True)

handle_allure = HandleAllure()

2.3testDatas

excel测试用例文件,必须是.xlsx结尾,用例结构如下:

图片

2.4conf

放置配置文件 .conf结尾

2.5 testCases

conftest.py

fixture功能,用例前置后置操作
构造测试数据
其他高级操作
注意邮件中的password和user_list需要换成自己测试的邮箱及服务密码
test_wanAndroid.py 测试用例脚本

参数化: pytest.mark.parametrize(‘case’,[{},{}])
接口关联:
将关联的参数配置成全局变量
在用例执行前使用全局变量替换参数
使用 is_run 参数指明有参数化的用例,并取出,再赋值给全局变量
cookies:
和接口关联的处理方式一样处理cookies
步骤
收集用例
执行用例
断言
构造测试报告
发送邮件

2.5.1 conftest.py

import pytest
from base.base_path import *
from utils.handle_logger import logger
from utils.handle_allure import handle_allure
from utils.handle_sendEmail import HandleSendEmail

'''
1. 构造测试数据??
2. fixture 替代 setup,teardown
3. 配置 pytest
'''

def pytest_collection_modifyitems(items):
    """
    测试用例收集完成时,将收集到的item的name和nodeid的中文显示在控制台上
    """
    for item in items:
        item.name = item.name.encode("utf-8").decode("unicode_escape")
        item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")
        # print(item.nodeid)

@pytest.fixture(scope='session', autouse=True)
def send_email():
    logger.info('-----session级,执行wanAndroid测试用例-----')
    yield
    logger.info('-----session级,wanAndroid用例执行结束,发送邮件:-----')
    """执行alllure命令 """
    handle_allure.execute_command()
    # 发邮件
    part_text = '附件为自动化测试报告,框架使用了pytest+allure'
    attachment_list = [report_path]
    password = ''
    user_list = ['']
    HandleSendEmail(part_text, attachment_list, password, user_list).send_email()

2.5.2 test_wanAndroid.py

import json
import pytest
import allure
from base.base_requests import BaseRequests
from utils.handle_logger import logger
from utils.handle_excel import HandleExcel
from utils.param_replace import pr
from utils.handle_cookies import get_cookies

handle_excel = HandleExcel()
get_excel_data = HandleExcel().get_excel_data()
ID = ''
COOKIES = {}
PAGE = ''

class TestWanAndroid:

    @pytest.mark.parametrize('case', get_excel_data)
    def test_wanAndroid(self, case):
        global ID
        global COOKIES
        # 参数替换
        case['url'] = pr.relevant_parameter(case['url'], '${collect_id}', str(ID))

        if case['is_run'].lower() == 'yes':
            logger.info('------执行用例的id为:{0},用例标题为:{1}------'.format(case['case_id'], case['title']))
            res = BaseRequests(case, cookies=COOKIES).get_response()
            res_json = res.json()

            # 获取登录后的cookies
            if case['case_id'] == 3:
                COOKIES = get_cookies.get_cookies(res)

            if case['is_depend']:
                try:
                    ID = res_json['data']['id']
                    # 将使用的参数化后的数据写入excel
                    handle_excel.rewrite_value('id={}'.format(ID), case['case_id'], 'depend_param')
                except Exception as e:
                    logger.error(f'获取id失败,错误信息为{e}')
                    ID = 0

            # 制作 allure 报告
            allure.dynamic.title(case['title'])
            allure.dynamic.description('<font color="red">请求URL:</font>{}<br />'
                                       '<font color="red">期望值:</font>{}'.format(case['url'], case['excepted']))
            allure.dynamic.feature(case['module'])
            allure.dynamic.story(case['method'])

            result=''
            try:
                assert eval(case['excepted'])['errorCode'] == res_json['errorCode']
                result = 'pass'
            except AssertionError as e:
                logger.error('Assert Error:{0}'.format(e))
                result = 'fail'
                raise e
            finally:
                # 将实际结果格式化写入excel
                handle_excel.rewrite_value(json.dumps(res_json, ensure_ascii=False, indent=2, sort_keys=True), case['case_id'], 'actual')
                # 将用例执行结果写入excel
                handle_excel.rewrite_value(result, case['case_id'], 'test_result')


    def test_get_articleList(self):
        '''翻页,将page参数化'''
        global PAGE
        pass


    def test_mock_demo(self):
        '''使用mock服务模拟服务器响应'''
        pass


if __name__ == '__main__':
    pytest.main(['-q', 'test_wanAndroid.py'])

2.6 testReport

存放html测试报告,安装插件pip install pytest-html

存放allure测试报告,插件安装pip install allure-pytest

2.7 logs

存放日志文件

2.8 其他文件

run.py 主运行文件

pytest.ini 配置pytest的默认行为,运行规则等

requirements.txt 依赖环境

3.总结

allure有很多有趣的操作,甚至控制用例执行行为,有兴趣可以拓展,也可以看下之前的博客

实现框架的难点在接口依赖

  • 自动生成 pip freeze
  • 安装 pip -r install requirements.txt

接口自动化应避免复杂的接口依赖,复杂的依赖只会造成测试的不可控性

注意频繁的操作excel会消耗性能

有兴趣可以将本框架集合在Jenkins中

本文的demo接口均采用至本站,感谢作者提供的免费接口
https://www.wanandroid.com/

项目git地址:…(git加密了,后续补上))

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

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

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

相关文章

渗透测试信息搜集

注&#xff1a;太简陋了&#xff0c;不忍直视 渗透测试信息收集 黑盒测试&#xff1a;给域名 灰盒测试&#xff1a;给域名、账户(或密码) 白盒测试&#xff1a;给域名、账户、密码 授权书 对安全公司进行授权 攻防演习 是对个人进行授权 渗透测试&#xff1a;&#xff0…

2023快速成为接口测试高手:实用指南!

大量线上BUG表明&#xff0c;对接口进行测试可以有效提升产品质量&#xff0c;暴露手工测试时难以发现的问题&#xff0c;同时也能缩短测试周期&#xff0c;提升测试效率。但在实际执行过程中&#xff0c;接口测试被很多同学打上了“上手难&#xff0c;门槛高”的标签。 本文旨…

游戏测试大揭秘,帮你轻松过关!

游戏测试可以看作是软件测试的一个分支&#xff0c;黑盒测试最基本的要求是会玩游戏。小公司会要求测试能力更加全面的员工&#xff0c;其中除了功能测试还要会性能测试&#xff0c;兼容测试&#xff0c;弱网测试&#xff0c;自动化测试等。 游戏测试是游戏开发过程中必不可少…

系列九、声明式事务(xml方式)

一、概述 声明式事务(declarative transaction management)是Spring提供的对程序事务管理的一种方式&#xff0c;Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明&#xff0c;是指在配置文件中声明&#xff0c;用在Spring配置文件中声明式的处理事务来…

stack和queue

目录 stack 介绍 头文件 简单使用 constructor empty size top push pop swap 使用 queue 介绍 头文件 简单使用 constructor empty size front back push pop swap 使用 stack 介绍 栈 先进后出 头文件 #include <stack> 简单使用 constru…

ELK+kafka+filebeat企业内部日志分析系统

1、组件介绍 1、Elasticsearch&#xff1a; 是一个基于Lucene的搜索服务器。提供搜集、分析、存储数据三大功能。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布…

Fiddler 无法抓包手机 https 报文的解决方案来啦!!

解决手机https无法抓包的问题 当你测试App的时候&#xff0c;想要通过Fiddler/Charles等工具抓包看下https请求的数据情况&#xff0c;发现大部分的App都提示网络异常/无数据等等信息 这时候怎么解决呢&#xff1f; 以软件测试面试提刷题APP为例&#xff1a; Fiddler上的显示…

微信 H5 中实现客服功能的几种方式

微信 H5 中实现客服功能的几种方式 本文主要针对微信网页 H5 中的客服功能 一、使用微信客服接口及对话界面 服务号消息客服&#xff0c;当用户和公众号产生特定动作的交互时&#xff08;用户发送信息/点击自定义菜单/关注公众号/扫描二维码&#xff09;&#xff0c;微信将会…

rancher2.6 docker版本部署

1. 拉取镜像 docker pull rancher/rancher:v2.6.5 注&#xff1a; 上面命令中rancher的版本v2.6.5&#xff0c;仅仅是我因为我们环境中使用的k8s都是 1.20.1 到1.23.6 之间的版本。rancher支持的k8s版本&#xff0c;在github上查看&#xff1a;Release Release v2.6.5 ranche…

2048 数字合成大作战,Android小游戏开发

A. 项目描述 《2048》是一款经典的益智小游戏&#xff0c;它的目标是通过合并相同数字来达到2048这个最高分。 该游戏规则简单&#xff0c;玩家需要通过滑动屏幕来移动方块&#xff0c;相同数字的方块会合并成一个新的数字方块。这样的简单操作让人可以轻松上手。 《2048》小…

短视频ai剪辑矩阵分发saas系统源头技术开发

抖音账号矩阵系统是基于抖音开放平台研发的用于管理和运营多个抖音账号的平台。它可以帮助用户管理账号、发布内容、营销推广、分析数据等多项任务&#xff0c;从而提高账号的曝光度和影响力。 具体来说&#xff0c;抖音账号矩阵系统可以实现以下功能&#xff1a; 1.多账号多…

笔尖笔帽检测4:C++实现笔尖笔帽检测算法(含源码 可是实时检测)

笔尖笔帽检测4&#xff1a;C实现笔尖笔帽检测算法(含源码 可是实时检测) 目录 笔尖笔帽检测4&#xff1a;C实现笔尖笔帽检测算法(含源码 可是实时检测) 1.项目介绍 2.笔尖笔帽关键点检测方法 (1)Top-Down(自上而下)方法 (2)Bottom-Up(自下而上)方法&#xff1a; 3.笔尖笔…

举个栗子!Quick BI 技巧(4):创建面积图

面积图又叫区域图&#xff0c;是在折线图的基础之上形成的, 它将折线图中折线与自变量坐标轴之间的区域使用颜色或者纹理填充&#xff0c;这样一个填充区域我们叫做面积&#xff0c;颜色的填充也可以更好的突出趋势信息。 有数据粉好奇如何使用 Quick BI 来制作面积图&#xf…

网络安全工程师就业前景怎么样?

网络安全工程师的就业前景整体来看是不错的&#xff0c;近些年的岗位需求总体呈现上升的趋势&#xff0c;可以说只要有互联网的存在&#xff0c;就会有网络安全工程师的一席之地。不过现在企业更缺乏资深技术人才&#xff0c;如果只学会了皮毛&#xff0c;可能不会很好就业。 网…

「可移动工具车」物料管理的得力助手

随着工业制造企业不断发展&#xff0c;仓储的运营变得越来越重要&#xff0c;物料高效管理也迎来了新的挑战&#xff0c;工厂物料管理直接影响着生产效率和成本控制&#xff0c;不合理的物料管理可能导致物料溢出、过度库存、损耗增加等问题&#xff0c;进而影响企业的整体竞争…

OpenStack云计算平台-块存储服务

目录 一、块存储服务概览 二、安装并配置控制节点 1、先决条件 2、安全并配置组件 3、配置计算节点以使用块设备存储 4、完成安装 三、安装并配置一个存储节点 1、先决条件 2、安全并配置组件 3、完成安装 ​四、验证操作 一、块存储服务概览 OpenStack块存储服务(c…

了解5G安全标准,看这一篇就够了

随着移动通信系统在社会生活中的使用越来越广泛&#xff0c;特别是5G进一步以企业级应用作为核心应用场景&#xff0c;安全成为了包括5G在内的移动通信系统不可忽视的因素。本文梳理了全球主流移动通信标准化组织在安全方面的标准制定&#xff0c;从而可以快速了解5G协议层面对…

WorldWind Android上加载白模数据

这篇文章介绍下如何加载白模数据。这个白模数据的格式是shapefile格式的文件。白模数据拷贝到手机本地&#xff0c;然后读取白模数据&#xff0c;进行加载展示。 worldwind android本身是不支持加载白模数据的&#xff0c;但是可以根据现有提供的加载Polygons的方式&#xff0c…

5.1 Windows驱动开发:判断驱动加载状态

在驱动开发中我们有时需要得到驱动自身是否被加载成功的状态&#xff0c;这个功能看似没啥用实际上在某些特殊场景中还是需要的&#xff0c;如下代码实现了判断当前驱动是否加载成功&#xff0c;如果加载成功, 则输出该驱动的详细路径信息。 该功能实现的核心函数是NtQuerySys…

141.【Git版本控制-本地仓库-远程仓库-IDEA开发工具全解版】

Git-深入挖掘 (一)、Git分布式版本控制工具1.目标2.概述(1).开发中的实际常见(2).版本控制器的方式(3).SVN (集中版本控制器)(4).Git (分布版本控制器)(5).Git工作流程图 (二)、Git安装与常用命令1.Git环境配置(1).安装Git的操作(2).Git的配置操作(3).为常用的指令配置别名 (可…