文章目录

  • 自动化接口测试
  • 第一章
    • 一、项目相关:
      • 1.项目信息:
        • 1.1 项目介绍:
      • 2.接口信息:
        • 2.1 接口介绍:
        • 2.2 登录接口文档:
        • 2.3 用户中心个人信息:
        • 2.4 获取商品列表数据:
        • 2.5 添加到购物车:
        • 2.6 保存订单:
    • 二、接口测试框架:
      • 1.介绍:
        • 1.1 框架对比:
      • 2.流程:
        • 2.1 代码运行:
        • 2.2 jenkins运行:
  • 第二章 接口自动化框架编写
    • 一、项目及框架的搭建:
      • 1.工具:
        • 1.1 python:
        • 1.2 pycharm:
        • 1.3 git:
      • 2.框架目录:
        • 2.1 创建目录:
    • 二、接口用例编写:
      • 1.被测试的接口:
      • 2. 使用excel编写测试用例:
        • 2.1 表结构:
    • 三、Requests使用:
      • 1. 介绍及使用:
      • 2. 用例代码编写:
      • 3. 方法封装:
    • 四、配置文件:
      • 1. yaml的介绍与安装:
        • 1.1 Yaml介绍:
        • 1.2 Yaml安装:
        • 1.3 快速体验:
      • 2. 基本操作:
        • 2.1 字典:
        • 2.2 列表:
        • 2.3 相互嵌套:
      • 3.读取文件:
        • 3.1 单个文件:
        • 3.2 多个文件:
      • 4.配置文件设置:
    • 五、日志文件:
      • 1.介绍:
        • 1.1 简介:
        • 1.2 快速使用:
      • 2.基本使用:
        • 2.1 日志输出到控制台或文件:
        • 2.2 log级别:
        • 2.3 输出格式:
      • 3.封装工具类:
        • 3.1 封装Log工具类:
        • 3.2 重构配置文件:
        • 3.3 日志工具类应用
    • 六、pytesy框架:
      • 1.安装与入门:
        • 1.1 介绍:
      • 2.基础使用:
        • 2.1 函数级别方法:
        • 2.2 类级别方法:
      • 3. 常用插件:
        • 3.1 测试报告:
        • 3.2 失败重试:
      • 4. 数据参数化:
        • 4.1 传入单个参数:
        • 4.2 传入多个参数:
      • 5.应用接口用例:
        • 5.1 pytest运行原则:
          • 5.2.1 默认规则:
          • 5.2.2 自定义规则运行:
    • 七、结果断言:
      • 1.结果断言验证:
        • 1.1 常用断言:
        • 1.2断言应用接口用例:
        • 1.3断言封装
      • 2. 数据库结果断言验证:
        • 2.1 pymysql安装及简单实用:
        • 2.2 工具类封装及使用:
    • 八、数据驱动:
      • 1. yaml数据驱动:
        • 1.1 yaml测试用例:
        • 1.2 参数化:
      • 2. Excel数据驱动
        • 2.1 excel用例设计:
        • 2.2 excel读取:
        • 2.3 封装excel工具类:
        • 2.4 excel参数化运行:
        • 2,4 动态的headers请求
        • 2.5 动态关联:
        • 2.6 断言验证:
    • 九、Allure报告:
      • 1.快速入门:
        • 1.1 allure安装:
        • 1.2 allure使用:
      • 2. allure详解:
      • 3. Allure应用:
        • 3.1 应用测试用例:
          • 1) 区分层级:
          • 2) 自动生成测试报告:
        • 3.2 项目运行:
    • 十、邮件配置:
      • 1. 配置文件设置及邮件封装:
      • 2. 邮件运行:
  • 三、持续集成与docker介绍及配置:
    • 1. jenkins和docker介绍及安装:
      • 1.1 docker:
        • 1) 介绍:
        • 2)安装:
        • 3) docker拉取镜像慢:
        • 4) docker的基本用法:
      • 1.2 jenkins:
        • 1) 介绍:
        • 2) 安装:
        • 3) 启动jenkins:
    • 2. Jenkins插件安装及配置:
      • 2.1 allure:
        • 1)安装:
        • 2) 配置(Allure Commandline):
      • 2.2 git:
        • 1)安装:
        • 2) 配置:
    • 3. jenkins持续集成配置及运行:
      • 3.1 general:
        • 1) 创建项目
        • 2) 配置项目:
        • 3) 运行项目:
        • 4) 查看邮件:
        • 5) 查看报告:
      • 3.2 源码管理:
      • 3.3 其他配置:
      • 3.4 运行:
    • 4、拓展:
      • 4.1 学习网站:

自动化接口测试

第一章

一、项目相关:

1.项目信息:

1.1 项目介绍:

  • 项目名称: 美多商城
  • 项目访问访问网站: http://211.103.136.242:8062/

2.接口信息:

2.1 接口介绍:

  • 登录;
  • 个人信息;
  • 获取商品信息;
  • 购物车;
  • 订单;

2.2 登录接口文档:

  • 后端接口设计:

    • 请求方式: POST /authorizations/
    • 请求参数:
参数名 类型 说明
username str 用户名
password str 密码

返回数据

返回值 类型 说明
username str 用户名
user_id int 用户id
token str 身份认证

2.3 用户中心个人信息:

访问必须要求用户已通过认证(即登录之后)
认证:

headers:{'Authorization': 'JWT '+ this.token
}
  • 后端接口设计:

    • 请求方法: GET /user/
    • 返回数据:
返回值 类型 是否必须 说明
id int 用户id
username str 用户名
mobile str 手机号
email str email邮箱
email_active bool 邮箱是否通过验证

2.4 获取商品列表数据:

  • 业务需求:
    需要对商品数量进行分页支持,并且可以按照时间(默认)、价格、销量(人气)进行排序
  • 后端接口设计:
    • 请求方法: GET /categories/(?P<category_id>\d+)/skus>page=xxx&page_size=xxx&ordering=xxx
    • 请求参数:
参数 类型 是否必须 说明
category_id int 类别id(第三级类别)
page int 页数
page_size int 每页数量
ordering str 排序关键字(create_time, price, sales)

返回数据:

返回值 类型 是否必须 说明
id int 商品sku编号
name str 商品名称
price decimal 单价
default_image_url str 默认图片
comments int 评论数量

2.5 添加到购物车:

  • 后端接口:

    • 请求方法: POST /cart/
    • 请求参数:
参数 类型 是否必须 说明
sku_id int 商品sku_id
count int 数量
selected bool 是否勾选,默认勾选

返回数据:

参数 类型 是否必须 说明
sku_id int 商品sku_id
count int 数量
selected bool 是否勾选,默认勾选

访问此接口, 无论用户是否登录,前端请求都需要带请求头Authorization, 由后端判断是否登录.

2.6 保存订单:

  • 后端接口设计:

    • 请求方式: POST /orders/
    • 请求参数:
参数 类型 是否必须 说明
address int 收货地址id
pat_method int 支付方式

返回数据:

参数 类型 是否必须 说明
order_id char 订单编号

二、接口测试框架:

1.介绍:

1.1 框架对比:

  • Unittest:

    • 不支持失败自动重新执行;
    • 参数化需依赖三方库;
    • HTMLTestRunner三方报告不够美观
  • pytest:

    • 兼容unittest
    • 支持失败自动重新执行;
    • 参数化使用自带装饰器;
    • 兼容主流allure框架,报告美观功能强大;

2.流程:

2.1 代码运行:

Created with Raphaël 2.2.0主程序运行(pytest框架)Excel用例(数据驱动)配置文件(Yaml)Requests断言(结果断言、数据库断言)报告(Allure插件)邮件

2.2 jenkins运行:

Created with Raphaël 2.2.0Jenkins/DockerJob运行gitAllure邮件

)]

第二章 接口自动化框架编写

一、项目及框架的搭建:

1.工具:

1.1 python:

  • 下载地址: https://www.python.org/download

1.2 pycharm:

  • 下载地址: https://www.jetbrains.com/pycharm

1.3 git:

  • 下载地址: https://git-scm.com/download

2.框架目录:

2.1 创建目录:

InterAutoTest_W

### 3.配置(pycharm):

  • 配置python环境:
Setting ->Project ->Project Interpreter
  • 配置git:
Setting ->Version Control ->Git
  • 配置github:
Setting -> Version Control ->Github
  • 建立远程仓库并提交代码:
Vcs ->import into version control ->Share Project on Github

二、接口用例编写:

1.被测试的接口:

  • 登录;
  • 获取个人信息;
  • 获取商品信息;
  • 添加到购物车;
  • 保存订单;

2. 使用excel编写测试用例:

2.1 表结构:

  • 用例ID;
  • 模块;
  • 接口名称;
  • 请求URL;
  • 前置条件;
  • 请求类型;
  • 请求参数类型
  • 请求参数;
  • 预期结果;
  • 实际结果;
  • 备注;

三、Requests使用:

1. 介绍及使用:

  • 介绍:流行的接口http(s)请求工具, 功能强大,简单方便,容易上手;
  • 官网: http://cn.python-requests.org/zh_CN/latest/

2. 用例代码编写:

# coding=utf-8
import requests
r = requests.get('http://www.baidu.com')
print(r) # <Response [200]>
  • 请求返回介绍:
属性/方法 说明
r.status_code 响应状态码
r.content 字节方式的响应体,会自动解码gzip和deflate压缩
r.headers 以字典对象存储服务器响应头,若键不存在则返回None
r.json() Requests中内置的JSON
r.url 获取url
r.encoding 编码格式
r.cookies 获取cookie
r.raw 获取原始响应体
r.text 字符串方式的响应体,会自动根据响应头部的字符编码进行编码
r.raise_for_status() 失败请求(非200响应)抛出异常

3. 方法封装:

  • 1.创建封装方法
  • 2.发送requests请求
  • 3.获取结果相应内容
  • 4.内容存储到字典
  • 5.字典返回
    utils/Request.py
import requestsclass Request():def __init__(self,url):self.url = url# 定义公共方法:def request_api(self, uri, method='get', data=None,json=None, headers=None):if method == 'get':r = requests.get(self.url+uri, data=data, json=json, headers=headers)elif method == 'post':r = requests.post(self.url+uri, data=data, json=json, headers=headers)code = r.status_codetry:body = r.json()except:body = r.textres = {'code':code,'body':body}return res# 重构get方法def get(self, uri,**kwargs):return self.request_api(uri,**kwargs)def post(self, uri,**kwargs):return self.request_api(uri,method='post',**kwargs)

四、配置文件:

使用YAML语言编写配置文件

1. yaml的介绍与安装:

1.1 Yaml介绍:

  • yaml是一种所有编程语言可用的友好的数据序列化标准, 语法和其他高阶语言类似,并且可以简单表达字典、列表和其他基本数据类型的形态.
  • yaml格式作为文件的配置格式:
    • yaml支持注释;
    • 不必强求逗号、括号等符号;
    • 通过缩进来区分,视觉上清晰
  • yaml官网: https://yaml.org/

1.2 Yaml安装:

pip install PyYaml

1.3 快速体验:

  • 字典:字典里的键值对用’:'分隔;
    data.yml
name: "test_yaml"
result: "success"
import yamlwith open('./data.yml', 'r') as f:r = yaml.safe_load(f)print(r)
# {'name': 'test_yaml', 'result': 'success'}

2. 基本操作:

2.1 字典:

  • 字典里的键值对用’:'分隔;
  • 字典直接写key: value, 每个键值对占一行;
  • key: 后要跟空格

2.2 列表:

  • 一组按序列排列的值(简称"序列或列表");
  • 数组前加有"-"符号,符号与值之间需要用空格分隔;
- 12
- 32
- 33
# [12, 32, 33]

2.3 相互嵌套:

  • 字典嵌套字典:
person1:name: xiaomingage: 18
person2:name: xiaohongage: 16# person1': {'name': 'xiaoming', 'age': 18}, 'person2': {'name': 'xiaohong', 'age': 16}}
  • 字典嵌套列表:
person:- "a"- "b"- c# {'person': ['a', 'b', 'c']}
  • 列表嵌套列表:
- - 1- 2- 3
- "b"
- c
- - 6- 7- 8# [[1, 2, 3], 'b', 'c', [6, 7, 8]]
  • 列表嵌套字典:
- name: xiaomingage: 18
- 2
- 3
-name: xiaohongage: 16#  [{'name': 'xiaoming', 'age': 18}, 2, 3, {'name': 'xiaohong', 'age': 16}]

3.读取文件:

3.1 单个文件:

  • 中文乱码: open指定encoding*

data.yml

name: "test_yaml"
result: "success"
import yamlwith open('./data.yml', 'r') as f:r = yaml.safe_load(f)print(r)
# {'name': 'test_yaml', 'result': 'success'}

3.2 多个文件:

data.yml

---
name: "test_yaml"
result: "success"---
# 用'---'分隔,说明是多个文档
"用户名称1": "test123"
"密码":"123456"
import yamlwith open('./data.yml', 'r') as f:r = yaml.safe_load_all(f)
for i in r:print(r)
# {'name': 'test_yaml', 'result': 'success'}
# {"用户名称1": "test123","密码":"123456"}

4.配置文件设置:

  • yaml封装:
    ./utils/YamlUtil.py
# coding=utf-8# 1. 创建类
# 2. 初始化,文件是否存在
# 3. yaml读取import os
import yamlclass YamlReader():def __init__(self, yaml_p):if os.path.exists(yaml_p):self.yaml_p = yaml_pelse:raise FileNotFoundError("文件不存在")self._data = Noneself._data_all = Nonedef data(self):# 读取单个文档if not self._data:with open(self.yaml_p, 'r') as f:self._data = yaml.safe_load(f)return self._datadef data_all(self):# 读取单个文档if not self._data:with open(self.yaml_p, 'r') as f:self._data_all = list(yaml.safe_load_all(f))return self._data_all
  • 配置文件conf.yaml
    ./config/conf.yml
BASE:test:url: "http://211.103.136.242:8064"

./config/Conf.py

# coding=utf-8
import os
from utils.YamlUtil import YamlReader
# 1. 获取项目基本目录
# 1.2 获取当前项目的绝对路径
current = os.path.abspath(__file__)
BASE_DIR = os.path.dirname(os.path.dirname(current))
print(current, BASE_DIR)
# 1.3 定义config目录的路径
_config_path = BASE_DIR + os.sep + "config"def get_config_path():return _config_path
# 1.4 定义conf.yml的文件路径
_config_file = _config_path + os.sep + 'conf.yml'
def get_config_file():return _config_file# 2. 读取配置文件
class ConfigYaml():def __init__(self):self.config = YamlReader(get_config_file()).data()# 获取需要的信息def get_config_url(self):return self.config['BASE']['test']['url']if __name__ == "__main__":conf_read = ConfigYaml()print(conf_read)
  • 基本目录配置:

  • 配置文件读取及使用:

五、日志文件:

1.介绍:

1.1 简介:

logging模块是python内置的标准模块,主要用于输出运行日志, 可以设置输出日志等级、日志保存路径等.

1.2 快速使用:

log_demo.py

# coding=utf-8
# 1.导入logging包
import logging
# 2.设置配置信息
logging.basicConfig(level=logging.INFO, format="%(asctime)s-%(name)s-%(levelname)s-%(message)s")
# 3. 定义日志名称:get_logger
logger = logging.getLogger('log_demo')
# 4. info,debug
logger.info('info')
logger.debug('debug')
logger.warning('warning')# 2019-11-20 23:06:09,957-log_demo-INFO-info
# 2019-11-20 23:06:09,958-log_demo-WARNING-warning

2.基本使用:

2.1 日志输出到控制台或文件:

    1. 设置logger名称
    1. 设置log级别
    1. 创建handler, 用于输出控制台或写入文件
    1. 设置日志级别
    1. 定义handler的输出格式
    1. 添加handler
# coding=utf-8
import logging# 1. 设置logger名称
logger = logging.getLogger('log_file_demo')
# 2. 设置log级别
logger.setLevel(logging.INFO)
# 3. 创建handler, 用于输出控制台或写入文件
# 输出到控制台
fh_stream = logging.StreamHandler()
# 写入文件
fh_file = logging.FileHandler('./test.log')
# 4. 设置日志级别
fh_stream.setLevel(logging.INFO)fh_file.setLevel(logging.INFO)
# 5. 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
fh_stream.setFormatter(formatter)fh_file.setFormatter(formatter)
# 6. 添加handler
logger.addHandler(fh_stream)logger.addHandler(fh_file)# 7. 运行
logger.info('this is a info')
logger.debug('this is a debug')# 2019-11-20 23:29:13,977 log_file_demo INFO this is a info
# 因为debug的级别小于info,所以不输出debug

2.2 log级别:

2.3 输出格式:

Format格式说明:

格式 说明
%(levelno)s 打印日志级别的数值
%(levelname)s 打印日志级别名称
%(pathname)s 打印当前执行程序的路径,其实是sys.argv[0]
%(filename)s 打印当前执行程序名
%(funcName)s 打印日志的当前函数
%(lineno)d 打印诶之的当前行号
%(asctime)s 打印日志的时间
%(thread)d 打印线程ID
%(threadName)s 打印线程名称
%(process)d 打印线程ID
%(message)s 打印日志信息

3.封装工具类:

3.1 封装Log工具类:

utils/LogUtil.py

# coding=utf-8# 封装工具类
# 1.创建类
# 2.定义参数# 输出文件名称,Loggername,日志级别
# 3.编写输出到控制台或文件import logginglog_l = {"info": logging.INFO, "debug": logging.DEBUG,"warning": logging.WARNING,"error": logging.ERROR
}class logger():def __init__(self, log_file, log_name, log_level):self.log_file = log_file    # 扩展名, 配置文件self.log_name = log_name    # self.log_level = log_level# 设置log名称self.logger = logging.getLogger(self.log_nam)# 设置log级别self.logger.setLevel(log_l[self.log_level])# 判断handler是否存在if not self.logger.handlers:# 输出到控制台fh_stream = logging.StreamHandler()fh_stream.setLevel(log_l[self.log_level])formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')fh_stream.setFormatter(formatter)# 输出到文件fh_file = logging.FileHandler(self.log_file)fh_file.setLevel(log_l[self.log_level])fh_file.setFormatter(formatter)# 添加到handlerself.logger.addHandler(fh_stream)self.logger.addHandler(fh_file)

3.2 重构配置文件:

config/conf.yml

BASE:# log等级log_level: 'debug'# 扩展名log_extension: '.log'test:url: "http://211.103.136.242:8064"

3.3 日志工具类应用

config/Conf.py

# coding=utf-8
import os
from utils.YamlUtil import YamlReader
# 1. 获取项目基本目录
# 1.2 获取当前项目的绝对路径
current = os.path.abspath(__file__)
BASE_DIR = os.path.dirname(os.path.dirname(current))
print(current, BASE_DIR)
# 1.3 定义config目录的路径
_config_path =
# 1.4 定义conf.yml的文件路径
_config_file = _config_path + os.sep + 'conf.yml'# 定义logs文件路径
_log_path = BASE_DIR + os.sep + "logs"def get_config_path():return _config_pathdef get_config_file():return _config_filedef get_log_path():"""获取log文件路径"""return _log_path# 2. 读取配置文件
class ConfigYaml():def __init__(self):self.config = YamlReader(get_config_file()).data()# 获取需要的信息def get_config_url(self):return self.config['BASE']['test']['url']def get_conf_log(self):"""获取日志级别"""return self.config['BASE_DIR']['log_level']def get_conf_log_extension(self):return self.config['BASE_DIR']['log_extension']if __name__ == "__main__":conf_read = ConfigYaml()print(conf_read)print(conf_read.get_conf_log())print(conf_read.get_conf_log_extension())

utils/LogUtil.py

# 1.初始化参数数据
# 日志文件名称
log_path = Conf.get_log_path()
current_time = datetime.datetime.now().strftime('%Y-%m-%d')
log_extension = ConfigYaml().get_conf_log_extension()
logfile = os.path.join(log_path,current_time+log_extension)
print(logfile)# 日志文件级别
loglevel = ConfigYaml().get_conf_log()
print(loglevel)# 2. 对外方法: 初始化log工具类, 提供其他类使用
def my_log(log_name = __file__):return Logger(log_file=logfile, log_name=log_name, log_level=loglevel)if __name__ == "__main__":my_log().debug("this is a debug")

六、pytesy框架:

1.安装与入门:

1.1 介绍:

  • 简单灵活;
  • 容易上手;
  • 文档丰富;
  • 支持参数化

2.基础使用:

#coding=utf-8# 1. 创建简单的测试方法
# 2. pytest运行# 2.1 idea中直接执行# 2.2 命令行执行
import pytest# 创建普通的方法
def func(x):return x+1# 创建pytest断言的方法
def test_a():print("---test_a---")assert func(3) == 5 # 断言失败def test_b():print('---test_b---')assert func(3) == 4 # 断言成功# 代码直接执行
if __name__ == "__main__":pytest.main(["pytest_demo.py"])

使用命令行直接执行测试脚本:

pytest pytest_demo.py

2.1 函数级别方法:

  • 运行于测试方法的始末;
  • 运行一次测试函数会运行一次setup和teardown;
#coding=utf-8"""
1.定义类;
2.创建测试方法test开头
3.创建setup, teardown
4.运行查看结果
"""
import pytestclass TestFcun():def test_a(self):print('test_a')def test_b(self):print('test_b')def setup(self):print('------setup------')def teardown(self):print('------teardown------')if __name__ == "__main__":pytest.main(['-s', 'pytest_func.py'])"""
PS E:\学习\测试\InterAutoTest_W\testcase\t_pytest> python pytest_func.py
================================== test session starts ================================
platform win32 -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: E:\学习\测试\InterAutoTest_W, inifile: pytest.ini
plugins: remotedata-0.3.1, openfiles-0.3.2, doctestplus-0.3.0, arraydiff-0.3
collected 2 items                                                                                                                                                           pytest_func.py ------setup------
test_a
.------teardown------
------setup------
test_b
.------teardown------================= 2 passed in 0.08 seconds ==================
"""

2.2 类级别方法:

  • 运行于测试的始末;
  • 一个测试内只运行一次setup_class和teardown_class,不关心测试类内有多少测试函数
#coding=utf-8"""
1.定义类;
2.创建测试方法test开头
3.创建setup_class, teardown_class
4.运行查看结果
"""
import pytestclass TestClass():def test_a(self):print('test_a')def test_b(self):print('test_b')def setup_class(self):print('------setup_class------')def teardown_class(self):print('------teardown_class------')if __name__ == "__main__":pytest.main(['-s', 'pytest_class.py'])"""
PS E:\学习\测试\InterAutoTest_W\testcase\t_pytest> python pytest_class.py
=============== test session starts =================
platform win32 -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: E:\学习\测试\InterAutoTest_W, inifile: pytest.ini
plugins: remotedata-0.3.1, openfiles-0.3.2, doctestplus-0.3.0, arraydiff-0.3
collected 2 items                                                                                                                                                           pytest_class.py ------setup_class------
test_a
.test_b
.------teardown_class------============================ 2 passed in 0.04 seconds ==============================
"""

3. 常用插件:

  • 常用插件: https://plugincompat.herokuapp.com

3.1 测试报告:

  • 应用场景:

    • 自动化测试脚本最终是通过还是不通过,需要通过测试报告进行提现.
  • 安装:
pip install pytest-html
  • 使用

    • 在配置文件中的命令行参数中增加 --html=用户路径/report.html
./pytest.ini
[pytest]
addopts = --html=./report/report.html

执行测试脚本,生成测试脚本

3.2 失败重试:

  • 应用场景:

    • 当失败后尝试再次运行
  • 安装:
pip install pytest-rerunfailures
  • 使用:

    • 在配置文件中的命令行参数中增加 --reruns n (n表示重试的次数)
    • 如果期望加上出错重试等待的时间, --rerun-delay
./pytest.ini[pytest]
addopts = --html=./report/report.html --reruns 3 --reruns-delay=2
# 使用装饰器,控制单个测试用例的运行情况
@pytest.mark.flaky(reruns=3, reruns_delay=2)
def test_b():print('---test_b---')assert func(3) == 4 # 断言成功

在单个测试用例中设置运行控制,则不需要在配置文件中进行配置.

4. 数据参数化:

4.1 传入单个参数:

@pytest.mark.parametrize(argnames, argvalues)

  • argnames: 参数名;
  • argvalues:参数对应值,类型必须为可迭代类型,一般为list
# coding=utf-8
"""
1. 创建类和测试方法
2. 创建数据
3. 创建参数化
4.运行
"""
import pytestclass TestClass():data_list = ['xiaoming', 'xiaohong']@pytest.mark.parametrize('name',data_list)def test_a(self, name):print('test_a')print(name)assert 1if __name__ == "__main__":pytest.main(['-s','pytest_one.py'])'''
PS E:\学习\测试\InterAutoTest_W\testcase\t_pytest> python .\pytest_one.py
============== test session starts =================================
platform win32 -- Python 3.7.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.1
rootdir: E:\学习\测试\InterAutoTest_W, inifile: pytest.ini
plugins: arraydiff-0.3, doctestplus-0.3.0, html-2.0.1, metadata-1.8.0, openfiles-0.3.2, remotedata-0.3.1, rerunfailures-8.0
collected 2 items                                                                                                                                                           pytest_one.py test_a
xiaoming
.test_a
xiaohong
.--------- generated html file: file://E:\学习\测试\InterAutoTest_W\testcase\t_pytest\report\report.html ---------
=================== 2 passed in 0.05s =================
'''

4.2 传入多个参数:

@pytest.mark.parametrize((‘参数1’,‘参数2’), ([参数1_list], [参数2_list]))

  • list的每个元素都是一个元组,元组里的每个元素和参数是按顺序一一对应的
# coding=utf-8
"""
1. 创建类和测试方法
2. 创建数据
3. 创建参数化
4.运行
"""
import pytestclass TestClass():data_list = [('xiaoming', '12345'),('xiaohong', '56789')]@pytest.mark.parametrize(('name','psw'),data_list)def test_a(self, name,psw):print('test_a')print(name,psw)assert 1if __name__ == "__main__":pytest.main(['-s','pytest_more.py'])'''
PS E:\学习\测试\InterAutoTest_W\testcase\t_pytest> python .\pytest_more.py
======================= test session starts ======================
platform win32 -- Python 3.7.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.1
rootdir: E:\学习\测试\InterAutoTest_W, inifile: pytest.ini
plugins: arraydiff-0.3, doctestplus-0.3.0, html-2.0.1, metadata-1.8.0, openfiles-0.3.2, remotedata-0.3.1, rerunfailures-8.0
collected 2 items                                                                                                                                                           pytest_more.py test_a
xiaoming 12345
.test_a
xiaohong 56789
.------- generated html file: file://E:\学习\测试\InterAutoTest_W\testcase\t_pytest\report\report.html ----------------
===================== 2 passed in 0.06s ============================
'''

5.应用接口用例:

  • 登录;
  • 个人信息;
  • 获取商品信息;
  • 购物车;
  • 订单;

5.1 pytest运行原则:

5.2.1 默认规则:
  • 在不指定运行目录,运行文件,运行函数等参数的默认情况下, pytest会执行当前目录下所有的以test为前缀(test*.py)或以_test为后缀(_test.py)的文件中以test为前缀的函数.
# coding=utf-8"""
1. 根据默认运行原则,调整py文件命名,函数命名
2. pytest.main()运行,或者命令行直接运行
"""import syssys.path.append('../')
import pytest
import requests
from utils.RequestsUtil import Request, r_get,r_postrequest = Request(url='http://211.103.136.242:8064')def test_login():"""登录"""url = 'http://211.103.136.242:8064/authorizations/'data = {'username':'python', 'password':'12345678'}r = r_post(url, json=data)print(r)"""
PS E:\学习\测试\InterAutoTest_W\testcase> python .\test_mall.py
============================ test session starts ========================================
platform win32 -- Python 3.7.3, pytest-5.3.0, py-1.8.0, pluggy-0.13.1
rootdir: E:\学习\测试\InterAutoTest_W, inifile: pytest.ini
plugins: arraydiff-0.3, doctestplus-0.3.0, html-2.0.1, metadata-1.8.0, openfiles-0.3.2, remotedata-0.3.1, rerunfailures-8.0
collected 1 item                                                                                                                                                            test_mall.py {'code': 200, 'body': {'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6Ijk1MjY3MzYzOEBxcS5jb20iLCJleHAiOjE1NzQ4NTAyMzIsInVzZXJuYW1lIjoicHl0aG9uIiwidXNlcl9pZCI6MX0.GLoT8ncQu9Pd74x0EoVjiXdnKED6JsB4WkasS8d6aPw', 'username': 'python', 'user_id': 1}}
.--------- generated html file: file://E:\学习\测试\InterAutoTest_W\testcase\report\report.html -------------
========================= 1 passed in 2.34s =========================
"""
5.2.2 自定义规则运行:

使用pytest.ini文件配置:

./pytest.ini
addopts = -s
# 运行参数testpaths = testcases
# 当前目录下的script文件夹, -可自定义python_files = test_*.py
# 当前目录下的script文件夹下,以test_开头,以.py结尾的所有文件python_classes = Test_*
# 当前目录下的script文件夹下,以test_开头,以.py结尾的所有文件, 以Test_开头的类 -可自定义python_functions = test_*
# 当前目录下的script文件夹下,以test_开头,以.py结尾的所有文件, 以Test_开头的类, 以test_开头的方法 -可自定义

七、结果断言:

1.结果断言验证:

1.1 常用断言:

  • 介绍:

    • 断言是自动化最终的目的,一个用例没有断言,就失去了自动化测试的意义了;
    • 断言用到的是assert关键字;
    • 预期结果和实际结果做对比;
  • 常用断言:
情况 语句
判断x为真 assert x
判断x不为真 assert not x
判断b包含a assert a in b
判断a等于b assert a == b
判断a不等于b assert a != b

1.2断言应用接口用例:

  • 返回状态码:
  • 结果验证:

1.3断言封装

./utils/AssertUtil.py
# coding=utf-8
"""
1. 定义封装类;
2. 初始化数据,日志
3. code相等
4. body相等
5.body包含
"""
import json
from utils.LogUItil import my_logclass AssertUtil():def __init__(self):self.log = my_log('AssertUtil')def assert_code(self, code, expected_code):"""验证返回状态码"""try:assert int(code) == int(expected_code)return Trueexcept Exception as e:self.log.error(f'code error, code is {code}, expected_code is {expected_code}')raisedef assert_body(self, body, expected_body):"""验证返回结果内容相等"""try:assert body == expected_bodyreturn Trueexcept Exception as e:self.log.error(f'body error, body is {body}, expected_body is {expected_body}')raisedef assert_in_body(self, body, expected_body):"""验证返回结果是否包含期望的结果"""try:assert json.dumps(body) in json.dumps(expected_body)return Trueexcept Exception as e:self.log.error(f'body error, body not in expected_body, body is {body}, expected_body is {expected_body}')raise

2. 数据库结果断言验证:

2.1 pymysql安装及简单实用:

  • 安装:
pip install pymysql
  • 简单实用:
# coding=utf-8
"""
1. 导入pymysql
2. 链接database
3. 获取执行sql的光标对象
4. 执行sql
5. 关闭对象
"""
import pymysqlcnn = pymysql.connect(host='211.103.136.242',port=7090, user='test',password='test123456',database='meiduo',charset='utf8',)with cnn.cursor() as cursor:sql_str = 'select * from tb_users'cursor.execute(sql_str)res = cursor.fetchall()print(res)cnn.close()

2.2 工具类封装及使用:

  • pymysql工具类封装:
./utils/Mysqlutil.py
# coding=utf-8
"""
1. 创建封装类
2.初始化数据,连接数据库,光标对象
3. 创建查询,执行方法
4. 关闭对象
"""
import pymysql
import functoolsfrom utils.LogUItil import my_logclass Mysql():def __init__(self,host,user,password,database,port=3306,charset='utf8'):self.cnn = pymysql.connect(host=host,port=port,user=user,password=password,database=database,charset=charset)self.cursor = self.cnn.cursor()self.log = my_log()def __del__(self):try:self.cnn.close()except Exception as e:passtry:self.cursor.close()except Exception as e:passdef fetch_one(self, sql):"""查询一个对象"""self.cursor.execute(sql)return self.fetchone()def fetch_all(self, sql):"""查询全部对象"""self.cursor.execute(sql)return self.fetchall()def exec(self,sql):"""执行操作"""try:self.cursor.execute(sql)self.cursor.commit()except Exception as e:self.cnn.rollback()self.log.error(e)return Falsereturn Trueif __name__ == "__main__":mysql = Mysql(host='211.103.136.242',port=7090, user='test',password='test123456',database='meiduo',charset='utf8',)res = mysql.fetch_all('select * from tb_uders')print(res)
  • 配置文件:
# ./config/db_conf.yml
db_1:db_host: "211.103.136.242"db_port: 7090db_user: "test"db_password: "test123456"db_database: "meiduo"db_charset: "utf8"
./config/Conf.py
"""
1. 创建db_conf.yml
2. 编写数据库基本信息
3. 重构Conf.py
4. 执行
"""...# 定义db_conf.yml文件路径
_db_config_file = _config_path + os.sep + 'db_conf.yml'def get_db_conf_file():"""获取db_conf文件路径"""return _db_config_file# 2. 读取配置文件
class ConfigYaml():def __init__(self):self.config = YamlReader(get_config_file()).data()self.db_config = YamlReader(get_db_conf_file()).data()def get_db_conf_info(self, db_alias):"""根据db_alias获取数据库相关参数"""return self.db_config[db_alias]if __name__ == "__main__":conf_read = ConfigYaml()......print(conf_read.get_db_conf_info('db_1'))
  • 数据库结果验证:

      1. 初始化数据库信息,Base.py, init_db
      1. 接口用例返回结果内容进数据库验证
# ./common/Base.py# coding=utf-8
# 1.定义一个方法init_db
# 2.初始化数据库信息, 通过配置文件来完成
# 3.初始化mysql对象from config.Conf import ConfigYaml
from utils.MysqlUtil import Mysqldef init_db(db_alias):db_init = ConfigYaml().get_db_conf_info(db_alias)host = db_init.get('host', '127.0.0.1')port = int(db_init.get('port', 3306))user = db_init.get('user')database = db_init.get('database')password = db_init.get('password')charset = db_init.get('charset', 'utf8')conn = Mysql(host=host,port=port,user=user,password=password,database=database,charset=charset)return connif __name__ == "__main__":conn = init_db('db_1')print(conn)

八、数据驱动:

1. yaml数据驱动:

1.1 yaml测试用例:

#./data/testlogin.yml
# 登录的测试用例:# 测试名称:
# url地址
# data
# 期望结果
---
'case_name':"登陆成功用例"
'url': 'http://211.103.136.242:8064/authorizations/'
'data': 'username': "python"'password': "12345678"
'expect': "'username': 'python', 'user_id': 1"
---
'case_name':"登陆失败用例"
'url': 'http://211.103.136.242:8064/authorizations/'
'data': 'username': "test123456"'password': "1231111"
'expect': "'username': 'python', 'user_id': 1"

1.2 参数化:

# ./testcase/test_login.py# coding=utf-8# 1. 获取测试用例的列表# 获取testlogin.yml文件路径# 使用工具类来读取多个文档的内容
# 2. 参数化执行测试用例import os
import sys
sys.path.append("../")
import pytest
from config import Conf
from config.Conf import ConfigYaml
from utils.YamlUtil import YamlReader
from utils.RequestsUtil import Requesttest_file = os.path.join(Conf.get_data_path(), 'testlogin.yml')
print(test_file)data_list = YamlReader(test_file).data_all()
print(data_list)@pytest.mark.parametrize("login", data_list)
def test_yaml(login):"""执行测试用例"""uri = login['url']print(uri)data = login['data']print(data)request = Request(ConfigYaml().get_config_url())res = request.post(uri, json=data)print(res)if __name__ == "__main__":pytest.main(['test_login.py'])

2. Excel数据驱动

2.1 excel用例设计:

(./data/testdata.xlsx)

2.2 excel读取:

# coding=utf-8"""
1. 导入包, xlrd(python自带)
2. 创建workbook对象
3. sheet对象
4. 获取行数和列数
5. 读取每行的内容
6. 读取每列的内容
7. 读取固定列的内容
"""
import xlrd
book = xlrd.open_workbook('./testdata.xlsx')
# 获取表的两种方式:
# 索引
# sheet = book.sheet_by_index(0)
# 名称
sheet = book.sheet_by_name('美多商城接口测试')rows = sheet.nrows  # 行数
cols = sheet.ncols  # 列数
print(f"rows:{rows}, cols:{cols}")# 获取每行数据
for r in range(rows):r_values = sheet.row_values(r)print(r_values)# 获取每列数据
for c in range(cols):c_values = sheet.col_values(c)print(c_values)# 读取固定列的内容
v = sheet.cell(1,2)
print(v)

2.3 封装excel工具类:

# ./utils/ExcelUtil.py# coding=utf-8
# 目的: 参数化, pytest list# 1. 验证文件是否存在,存在读取,不存在错报
# 2. 读取sheet方式, 名称,索引
# 3. 读取sheet内容# 返回list, 字典# 格式: [{'a':"a1",'b':" b1"}, {'a':"a2",'b':"b2"}]
# 4. 结果返回import os
import xlrd# 自定义异常
class  SheetTypeError(object):passclass ExcelReader():def __init__(self, excel_file, sheet_by):if os.path.exists(excel_file):self.excel_file = excel_fileself.sheet_by = sheet_byself.data_list = []else:raise FileNotFoundError("文件不存在")def data(self):if self.data_list:return self.data_listworkbook = xlrd.open_workbook(self.excel_file)if type(self.sheet_by) not in [str,int]:raise SheetTypeError("参数错误")elif type(self.sheet_by) == int:sheet = workbook.sheet_by_index(self.sheet_by)elif type(self.sheet_by) == str:sheet = workbook.sheet_by_name(self.sheet_by)# 获取首行信息title = sheet.row_values(0)for r in range(1, sheet.nrows):self.data_list.append(dict(zip(title,sheet.row_values(r))))# print(self.data_list)return self.data_listif __name__ == "__main__":excel_reader = ExcelReader('../data/testdata.xlsx',"美多商城接口测试")print(excel_reader.data())

2.4 excel参数化运行:

  • 获取是否运行;
  • 参数化;
  • 结果断言;
# ./common/ExcelConfig.py
# coding=utf-8# 定义类
# 定义列属性
# 定义excel的映射class DataConfig():# 用例属性:case_id = "用例ID"case_model = "模块"case_name = "接口名称"  url = "请求URL"    pre_exec = "前置条件"    method = "请求类型"  params_type = "请求参数类型"   params = "请求参数"  expect_result = "预期结果"   actual_result = "实际结果"   beizhu = "备注"    is_run = "是否运行"  headers = "headers"  cookies = "cookies"  code = "status_code"     db_verify = "数据库验证"
# ./config/ExcelData.py
# coding=utf-8# 1. 使用excel工具类, 获取结果list
# 2. 列"是否运行内容", y
# 3. 保存要执行结果, 放到新的列表中
import sys
sys.path.append('../')
from utils.ExcelUtil import ExcelReader
from common.ExcelConfig import DataConfigclass Data():def __init__(self, excel_file, sheet_by):self.reader = ExcelReader(excel_file, sheet_by)self.run_list = []def get_run_data(self):"""根据"是否运行"列,获取执行测试用例"""for line in self.reader.data():if str(line[DataConfig().is_run]).lower() == 'y':self.run_list.append(line)return self.run_list

2,4 动态的headers请求

    1. 判断header是否存在? json转义: 无需
    1. 增加Headers
    1. 增加cookies
    1. 发送请求

2.5 动态关联:

    1. 验证前置条件;
    1. 找到执行用例;
    1. 发送请求,获取前置用例结果;
    • 发送获取前置用例;
    • 数据初始化, 重构get/post
    1. 替换headers变量;
    • 验证请求中师傅含有()()(), 返回()()()内容
    • 根据内容token,查询前置条件用例返回结果
    • 根据变量结果内容,替换
    1. 发送请求

2.6 断言验证:

  • 状态码;
  • 返回结果内容;
  • 数据库相关结果的验证
      1. 初始化数据库;
      1. 查询sql语句;
      1. 获取数据库结果的key;
      1. 根据key获取数据库结果和接口结果
      1. 验证

九、Allure报告:

1.快速入门:

1.1 allure安装:

  • python插件:

    • 命令行安装:
pip install allure-pytest
- 源代码安装:
htpps://pypi.org/project/allure-pytest
  • allure工具:

    • 下载:
      https://bintray.com/qameta/generic/allure2
      https://github.com/allure-framework/allure2
    • 前置条件:
      • 已部署java环境
    • 解压并配置系统环境变量;

1.2 allure使用:

  • 配置pytest.ini
[pytest]
# addopts = -s --html=./report/report.html --reruns 3 --reruns-delay=2# allure setting
addopts = -s --allure ./report/report.html
...
  • 添加allure代码;
  • 运行;
  • allure工具生成html报告;
allure generate {result_path} -o {report_path}
or
allure generate {result_path} -o {report_path} --clean

2. allure详解:

注解 说明
Title 可以自定义用例标题, 标题默认函数名
Description 测试用例的详细说明
Feature 定义功能模块, 往下是Story
Story 定义用户故事
Severity 定义用例级别,主要有BLOCKER(拦截器), CRITICAL(关键), MINOR(次要), NORMAL(正常), TRIVIAL(琐碎)等几种类型,默认是NORMAL
Allure.dynamic 动态设置相关配置
# coding=utf-8import pytest
import allure@allure.feature('接口测试, 这是一个一级标签')
class TestAllure():# 定义测试方法@allure.title('测试用例标题1')@allure.description('执行测试用例1的结果是:test_1')@allure.stroy("这是一个二级标签:test1")@allure.severity(allure.severity.CRITICAL)def test_1(self):print("test_1")@allure.title('测试用例标题2')@allure.description('执行测试用例2的结果是:test_2')@allure.stroy("这是一个二级标签:test1")@allure.severity(allure.severity.BLOCKER)def test_2(self):print("test_2")@allure.title('测试用例标题3')@allure.description('执行测试用例3的结果是:test_3')@allure.stroy("这是一个二级标签:test3")def test_3(self):print("test_3")@pytest.mark.parametrize("case",['case1', 'case2', 'case3'])def test_4(self, case):print(f"test4: {case}")allure.dynamic.title(case)if __name__ == "__main__":pytest.main(['allure_demo.py'])

3. Allure应用:

3.1 应用测试用例:

1) 区分层级:
  • sheet名称 --> feature一级标签
  • 模块 --> story 二级标签
  • 用例id+接口名称 --> title
  • 请求url,请求类型,期望结果, 实际结果描述
# ./tesecase/test_excel_case.py...
class TestExcel():...@pytest.mark.parametrize('case', run_list)def test_run(self,case):...print(f"执行测试用例:{res}")# allureallure.dynamic.feature(sheet_name)allure.dynamic.story(case_model)allure.dynamic.title(case_id + case_name)desc = f"url:{url}<br> 请求方法:{method}<br> 期望结果:{expect_result}<br> 实际结果:{res}"allure.dynamic.description(desc)# 断言验证...
2) 自动生成测试报告:

不用再手动执行生成allure的html报告

  • subprocess介绍:

    • 允许生产新的进程,并且可以把输入,输出,错误直接连接到管道,最后获取结果
  • 官方网站:
    • https://docs.python.org/3.8/library/subprocess.html
  • 方法:
    • subprocess.all(): 父进程等待子进程完成, 返回退出信息(returncode, 相当于linux exit code)
    • shell=True的用法, 支持命令以字符串的形式传入
# ./common/Base.pydef allure_report(report_path):allure_cmd = f"allure generate {report_path}/result -o {report_path}/html --clean"log.info(f"报告地址:{report_path}")try:subprocess.call(allure_cmd, shell=True)except Exception as e:log.error(e)

3.2 项目运行:

十、邮件配置:

1. 配置文件设置及邮件封装:

(略)

2. 邮件运行:

(略)

三、持续集成与docker介绍及配置:

1. jenkins和docker介绍及安装:

1.1 docker:

1) 介绍:

  • 开源免费;
  • 方便快速搭建环境;
  • 自动化测试和持续集成,发布;

2)安装:

  • 流程:(基于centos)

      1. 查看内核版本;
      1. 安装需要的软件包;
      1. 设置yum源;
      1. 查询及安装docker;
      1. 启用docker, 并加入开机启动;

3) docker拉取镜像慢:

将镜像源修改为阿里云镜像源

    1. 编辑docker配置文件:
vi /lib/systemd/system/docker.service
    1. 修改配置内容:
ExecStart=/usr/bin/docker
修改为:
ExecStart=/usr/bin/docker --registry-mirror=https://u1qbyfsc.mirror.aliyuncs.com

4) docker的基本用法:

常用命令 说明
docker images 列出本地主机上的镜像
docker ps -a 查看容器状态
docker start(stop,restart) container-name 容器启动(关闭,重启)命令
docker exec 进入正在后台执行的容器(参数:-d: 分离模式,在后台执行; -i: 即使没有附加也保持STDIN打开; -t: 分配一个伪终端)

1.2 jenkins:

1) 介绍:

  • 开源免费;
  • 安装配置简单;
  • 跨平台,支持所有平台;
  • web形式的可视化管理页面;
  • 分布式构建;
  • 丰富的插件支持;

2) 安装:

系统: centos; 容器: docker

    1. 选择docker版本安装;
    • https://jenkins.io/zh/download/
    1. 安装;
    1. 查看下载完的镜像;
    1. 启动jenkins镜像;
    1. 浏览http://localhost 并等待Unlock Jenkins页面出现;
    1. 使用后面的步骤设置向导完成设置;

3) 启动jenkins:

docker run -d -p 80:8080 -p 50000:50000 -v jenkins:/var/jenkins_home -v /etc/localtime:/etc/localtime --name jenkins docker.io/jenkins/jenkins:lts
  • 启动参数意义:
参数 意义
-d 后台运行
-p 80:8080 将镜像的8080端口映射到服务器的80端口
-p 50000:50000 将镜像的50000端口映射到服务器的50000端口
-v jenkins:/var/jenkins_home /var/jenkins_home目录为jenkins工作目录,将硬盘上的一个目录挂载到这个位置, 方便后续更新镜像后继续使用原来的工作目录
-v /etc/localtime:/etc/localtime 让容器使用和服务器使用同样的时间设置
–name jenkins 给容器起个名

2. Jenkins插件安装及配置:

2.1 allure:

1)安装:

    1. 进入jenkins -> 系统管理 -> 管理插件 -> 可选插件
    1. 搜索框输入"allure" -> 选中点击"直接安装" -> 等待安装完成 -> 重启jenkins

2) 配置(Allure Commandline):

  • 设置路径:

    • 系统设置 -> 全局工具配置 -> Allure Commandline
    1. Allure下载地址:
    • https://dl.bintray.com/qameta/generic/io/qameta/allure/2.7.0
    1. Allure安装:
    • 解压到本地, 配置环境变量即可.

2.2 git:

1)安装:

git是默认安装的

2) 配置:

    1. 系统管理 -> 全局工具配置 -> git
    1. 点击"添加" -> 输入name,path

3. jenkins持续集成配置及运行:

3.1 general:

1) 创建项目

    1. 进入jenkins主页;
    1. 点击"新建";
    1. 输入项目名称, 并点击"构建一个自由风格的软件项目";
    1. 点击"确定"

2) 配置项目:

    1. General;
    • a. 节点配置:

      • 系统管理 -> 节点管理 -> 新建节点
      • windows为例:
      • 工作目录: 工作目录
      • 启动方式: “通过java web启动代理”
    • b. 选择"在必要的时候并发构建"
    • c. 选择"限制项目的运行节点" -> 输入要运行的节点
    • 点击"保存"
    1. 源码管理;
    • a. 选择"Git";
    • b. 输入git地址;
    • c. 添加jenkins凭证认证;
    1. 构建触发器;

      • 第一颗 * 表示分钟, 取值0~59
      • 第二颗 * 表示小时, 取值0~23
      • 第三颗 * 表示一个月的第几天, 取值1~31
      • 第四颗 * 表示一周中的第几天, 取值0~7, 其中0和7代表的都是周日
    1. 构建配置;
    • 增加构建步骤:

      • windows:

        • Execute Windows batch command
      • linux/Mac:
        • Execute shell
    • 编写run.py
# ./run.py
# coding=utf-8
import os
import pytest
from config import Confif __name__ == "__main__":report_path = Conf._report_path()pytest.main(['-s', '--alluredir', report_path+'/reslut'])
    1. 报告;
      1. 点击增加构建后步骤,选择"Allure Report";
      1. 在path中输入allure报告所在的目录名称;
    1. 邮件;
      1. jenkins -> 系统配置 -> 邮件通知
      1. 设置相关信息;
      1. 构建后的操作 -> 增加构建有的操作步骤 -> E-mail notification -> 接收邮箱

3) 运行项目:

  • 自动构建:

  • 手动构建:

    • jenkins -> 立即构建 -> 点击进度条 -> 点击"控制台输出" -> 查看报错信息

4) 查看邮件:

5) 查看报告:

3.2 源码管理:

3.3 其他配置:

3.4 运行:

4、拓展:

4.1 学习网站:

  • Dokcker安装jenkins:

    • https://github.com/jenkinsci/docker/blob/master/README.md
  • Docker使用:
    • https://www.runoob.com/docker/docker-container-usage.html

测试-自动化接口测试相关推荐

  1. 测试中如何管理外包质量_如何从测试自动化中实现价值

    如果几年前,质量管理部门都试图通过ROI指标来证明对测试的投资是合理的,那么现在情况发生了变化,是时候重新审视这个问题了.当实施连续测试,并且每天在不同的环境下以不同的角色运行多次测试自动化时,由于测 ...

  2. Postman最被低估的功能,自动化接口测试效率简直无敌

    Postman自动化接口测试 该篇文章针对已经掌握 Postman 基本用法的读者,即对接口相关概念有一定了解.已经会使用 Postman 进行模拟请求的操作. 当前环境: Window 7 - 64 ...

  3. android冒烟测试自动化,安卓自动化测试总结(五)——测试结果发送及内容展示...

    安卓自动化测试总结(五)--测试结果发送及内容展示 使用jenkins自动构建并完成自动化测试后,如果想看测试结果,都需要打开jenkins构建地址,找到对应的构建及构建结果.这样做很麻烦,关心自动化 ...

  4. Postman最被低估的功能,自动化接口测试效率简直无敌!

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/cai_iac/article/details/81030619 Postman自动化接口测试 该篇文章针对已经掌握 Postm ...

  5. Postman自动化接口测试实战详解

    背景描述 有一个项目要使用postman进行接口测试,接口所需参数有: appid: 应用标识: sign:请求签名,需要使用HMACSHA1加密算法计算,签名串是:{appid}${url}${st ...

  6. 测试自动化金字塔在软件开发中是如何使用的?

    测试自动化金字塔,是一个指南,指导您进行什么类型的测试以及每种测试的数量.测试自动化金字塔有助于创建更高效的测试,并导致向客户发布更可靠的软件. 测试自动化金字塔的好处 测试自动化的大部分好处显而易见 ...

  7. 手动测试是进入测试自动化之前的重要阶段

    对与繁琐的软件测试工作自动化测试给我们带来的便利,但是在自动化测试之前软件产品也需要进行手动测试,如果您想详细了解什么是手动测试及其用途,一航软件测评的团队将帮助您弄清楚. 第三方软件检测机构知道如何 ...

  8. 从“三只小猪”的故事到“高性能”测试自动化

    持续部署越来越受欢迎,因此组织对于高性能测试的需要也越来越多. GoodRx的质量工程部门主管Priyanka Halder,在2020年1月举行的Applitools网络研讨会上,介绍了GoodRx ...

  9. Windows下搭建ant+jenkins+jmeter自动化接口测试框架

    Windows下搭建ant+jenkins+jmeter自动化接口测试框架 引言 为什么要持续集成? 1.减少风险 2.减少假定 3.减少重复过程 4.增强项目的可见性 5.持续集成可以带来两点积极效 ...

最新文章

  1. 巧用Excel 2010数据透视表制作销售报表
  2. Spring请求参数校验
  3. 在html中写js提示错误,页面HTML标签优化
  4. 漫步线性代数十九——快速傅里叶变换(上)
  5. 如何准确估计机器人的状态,增强机器人控制的精度及稳定性
  6. V-SQL的简单使用
  7. python 制作抽奖箱_丽水本地抽奖箱制作公司,抽奖箱制作-优质服务!
  8. 年轻人如何去有效的学习(很好的鸡汤,一语惊醒梦中人)
  9. red5源码分析---1
  10. Unity 2D 入门
  11. 用VASP+VTST计算Raman光谱 (抛砖引玉)
  12. 火星坐标系转百度php,PHP版本实现火星,高德地图和百度地图坐标转换
  13. 谷歌外链建设2022年如何判断和购买google优质外链
  14. 人工智能机器学习底层原理剖析,人造神经元,您一定能看懂,通俗解释把AI“黑话”转化为“白话文”
  15. go http客户端设置ResponseHeader参数后返回Timeouthttp: ContentLength=xxx with Body length 0错误
  16. 法律部门和法律体系(概念、我国现行的法律部门和法律体系 )、法 律 关 系(概念、构成要素:主体、内容、客体)、法律事实(法律事件、法律行为)
  17. 【黑客游戏】学习知识又能玩游戏
  18. 服务没有注册到nacos的原因分析
  19. 交叉验证的几个方法的解释(简单交叉验证、k折交叉验证、留一法)
  20. 软件测试实战(微软技术专家经验总结)--第五章(测试技术)读书笔记

热门文章

  1. 【五校联盟集训】DAY 1
  2. python前景和待遇-2020年Python的就业薪资有多少?前景如何?
  3. thinkadmin验证器与场景验证
  4. java中strings1等于s2_s1,s2都是String对象,说说表达式s1==s2与s1.equal(s2
  5. 【附源码】计算机毕业设计JAVA高考志愿智能辅助填报系统
  6. 《百面机器学习》读书笔记(十一)-强化学习
  7. windows11 如何关闭防火墙
  8. 重磅发布 | Serverless 应用中心:Serverless 应用全生命周期管理平台
  9. (完整版)马克思主义发展史复习重点
  10. ESP32 安装Arduino IED 2.0.3