目录:
1.pytest结合数据驱动-yaml
数据驱动
什么是数据驱动?
应用:
yaml 文件介绍
# 编程语言
languages:
- PHP
- Java
- Python
book:
Python入门: # 书籍名称
price: 55.5
author: Lily
available: True
repertory: 20
date: 2018-02-17
Java入门:
price: 60
author: Lily
available: False
repertory: Null
date: 2018-05-11
yaml 文件使用
pip install pyyaml
yaml.safe_load(f)
yaml.safe_dump(f)
import yaml
file_path = './my.yaml'
with open(file_path, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
代码实例:
工程目录结构
# 工程目录结构
.
├── data
│ └── data.yaml
├── func
│ ├── __init__.py
│ └── operation.py
└── testcase
├── __init__.py
└── test_add.py
测试准备
operation.py
test_add.py
data.yaml
# operation.py 文件内容
def my_add(x, y):
result = x + y
return result
# test_add.py 文件内容
class TestWithYAML:
@pytest.mark.parametrize('x,y,expected', [[1, 1, 2]])
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
# data.yaml 文件内容
-
- 1
- 1
- 2
-
- 3
- 6
- 9
-
- 100
- 200
- 300
import pytest
import yaml
from func.operation import my_add
# 方法一
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', [[1, 1, 2], [3, 6, 9], [100, 200, 300]])
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法二
def get_data():
with open("../data/data.yaml", encoding='utf-8') as f:
data = yaml.safe_load(f)
return data
class TestWithYAML:
@pytest.mark.parametrize('x,y,expected', get_data())
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
2.pytest结合数据驱动-excel
读取 Excel 文件
第三方库
xlrd
xlwings
pandas
openpyxl
openpyxl 库的安装
pip install openpyxl
import openpyxl
openpyxl 库的操作
读取工作簿
读取工作表
读取单元格
import openpyxl
# 获取工作簿
book = openpyxl.load_workbook('./data/test.xlsx')
# 读取工作表
sheet = book.active
print(sheet)
# 读取单个单元格
cell_a1 = sheet['A1']
print(cell_a1.value)
cell_a3 = sheet.cell(column=1, row=3) # A3
print(cell_a3.value)
# 读取多个连续单元格
cells = sheet["A1":"C3"]
for i in cells:
for j in i:
print(j.value,end=' ')
print()
代码实例:
import openpyxl
import pytest
import yaml
from func.operation import my_add
# 方法一
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', [[1, 1, 2], [3, 6, 9], [100, 200, 300]])
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法二
# def get_data():
# with open("../data/data.yaml", encoding='utf-8') as f:
# data = yaml.safe_load(f)
# return data
#
#
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', get_data())
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法三
def get_excel():
book = openpyxl.load_workbook("../data/test.xlsx")
sheet = book.active
cells = sheet["A1":"C3"]
values = []
for row in cells:
data = []
for cell in row:
data.append(cell.value)
values.append(data)
return values
class TestWithYAML:
@pytest.mark.parametrize('x,y,expected', get_excel())
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
3.pytest结合数据驱动-csv
csv 文件介绍
Linux从入门到高级,linux,¥5000
web自动化测试进阶,python,¥3000
app自动化测试进阶,python,¥6000
Docker容器化技术,linux,¥5000
测试平台开发与实战,python,¥8000
csv 文件使用
读取数据
open()
csv
方法:csv.reader(iterable)
import csv
def get_csv():
with open('./data/params.csv', 'r', encoding='utf-8') as file:
raw = csv.reader(file)
for line in raw:
print(line)
if __name__ == '__main__':
get_csv()
代码实例:
测试准备
被测对象:operation.py
测试用例:test_add.py
测试数据:params.csv
# operation.py 文件内容
def my_add(x, y):
result = x + y
return result
# test_add.py 文件内容
class TestWithCSV:
@pytest.mark.parametrize('x,y,expected', [[1, 1, 2]])
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
# params.csv 文件内容
1,1,2
3,6,9
100,200,300
import csv
import openpyxl
import pytest
import yaml
from func.operation import my_add
# 方法一
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', [[1, 1, 2], [3, 6, 9], [100, 200, 300]])
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法二
# def get_data():
# with open("../data/data.yaml", encoding='utf-8') as f:
# data = yaml.safe_load(f)
# return data
#
#
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', get_data())
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法三
# def get_excel():
# book = openpyxl.load_workbook("../data/test.xlsx")
# sheet = book.active
# cells = sheet["A1":"C3"]
# values = []
# for row in cells:
# data = []
# for cell in row:
# data.append(cell.value)
# values.append(data)
# return values
#
#
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', get_excel())
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法四
def get_csv():
with open('../data/test.csv', encoding='utf-8') as f:
raw = csv.reader(f)
data = []
for line in raw:
data.append(line)
return data
class TestWithYAML:
@pytest.mark.parametrize('x,y,expected', get_csv())
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
4.pytest结合数据驱动-json
json 文件介绍
json 是 JS 对象
全称是 JavaScript Object Notation
是一种轻量级的数据交换格式
json 结构
{"key": value}
[value1, value2 ...]
{
"name:": "tom",
"detail": {
"course": "python",
"city": "北京"
},
"remark": [1000, 666, 888]
}
json 文件使用
json.loads()
json.dumps()
params.json
{
"case1": [1, 1, 2],
"case2": [3, 6, 9],
"case3": [100, 200, 300]
}
import json
def get_json():
with open('./data/params.json', 'r') as f:
data = json.loads(f.read())
print(data)
print(type(data))
s = json.dumps(data, ensure_ascii=False)
print(s)
print(type(s))
if __name__ == '__main__':
get_json()
代码示例:
测试准备
被测对象:operation.py
测试用例:test_add.py
测试数据:params.json
# operation.py 文件内容
def my_add(x, y):
result = x + y
return result
# test_add.py 文件内容
class TestWithJSON:
@pytest.mark.parametrize('x,y,expected', [[1, 1, 2]])
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
# params.json 文件内容
{
"case1": [1, 1, 2],
"case2": [3, 6, 9],
"case3": [100, 200, 300]
}
import csv
import json
import openpyxl
import pytest
import yaml
from func.operation import my_add
# 方法一
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', [[1, 1, 2], [3, 6, 9], [100, 200, 300]])
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法二
# def get_data():
# with open("../data/data.yaml", encoding='utf-8') as f:
# data = yaml.safe_load(f)
# return data
#
#
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', get_data())
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法三
# def get_excel():
# book = openpyxl.load_workbook("../data/test.xlsx")
# sheet = book.active
# cells = sheet["A1":"C3"]
# values = []
# for row in cells:
# data = []
# for cell in row:
# data.append(cell.value)
# values.append(data)
# return values
#
#
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', get_excel())
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法四
# def get_csv():
# with open('../data/test.csv', encoding='utf-8') as f:
# raw = csv.reader(f)
# data = []
# for line in raw:
# data.append(line)
# return data
#
#
# class TestWithYAML:
# @pytest.mark.parametrize('x,y,expected', get_csv())
# def test_add(self, x, y, expected):
# assert my_add(int(x), int(y)) == int(expected)
# 方法五
def get_json():
with open('../data/params.json', 'r') as f:
data = json.loads(f.read())
print(data)
print(type(data))
print(list(data.values()))
return list(data.values())
class TestWithYAML:
@pytest.mark.parametrize('x,y,expected', get_json())
def test_add(self, x, y, expected):
assert my_add(int(x), int(y)) == int(expected)
5.pytest测试用例生命周期管理(一)
Fixture 特点及优势
Fixture 在自动化中的应用- 基本用法
测试⽤例执⾏时,有的⽤例需要登陆才能执⾏,有些⽤例不需要登陆。
setup 和 teardown ⽆法满⾜。fixture 可以。默认 scope(范围)function
import pytest
@pytest.fixture()
def login():
print('完成登录操作')
def test_search():
print('搜索')
# def test_cart():
# login()
# print('购物车')
def test_cart(login):
print('购物车')
def test_order(login):
print('下单功能')
6.pytest测试用例生命周期管理(二)
Fixture 在自动化中的应用 - 作用域
取值 | 范围 | 说明 |
---|---|---|
function | 函数级 | 每一个函数或方法都会调用 |
class | 类级别 | 每个测试类只运行一次 |
module | 模块级 | 每一个.py 文件调用一次 |
package | 包级 | 每一个 python 包只调用一次(暂不支持) |
session | 会话级 | 每次会话只需要运行一次,会话内所有方法及类,模块都共享这个方法 |
import pytest
@pytest.fixture(scope="function")
def login():
print('完成登录操作')
def test_search():
print('搜索')
# def test_cart():
# login()
# print('购物车')
def test_cart(login):
print('购物车')
def test_order(login):
print('下单功能')
class TestDemo:
def test_case1(self, login):
print("case1")
def test_case2(self, login):
print("case2")
7.pytest测试用例生命周期管理(三)
Fixture 在自动化中的应用 - yield 关键字
你已经可以将测试⽅法【前要执⾏的或依赖的】解决了,测试⽅法后销毁清除数据的要如何进⾏呢?
通过在 fixture 函数中加⼊ yield 关键字,yield 是调⽤第⼀次返回结果,第⼆次执⾏它下⾯的语句返回。
在@pytest.fixture(scope=module)。在登陆的⽅法中加 yield,之后加销毁清除的步骤
import pytest
'''
@pytest.fixture
def fixture_name():
setup 操作
yield 返回值
teardown 操作
'''
@pytest.fixture(scope="function")
def login():
#setup操作
print('完成登录操作')
tocken = "abcdafafasdfds"
username = 'tom'
yield tocken,username #相当于return
#teardown操作
print('完成登出操作')
def test_search():
print('搜索')
# def test_cart():
# login()
# print('购物车')
def test_cart(login):
print('购物车')
def test_order(login):
print('下单功能')
class TestDemo:
def test_case1(self, login):
print("case1")
def test_case2(self, login):
print("case2")
8.pytest测试用例生命周期管理-自动注册
Fixture 在自动化中的应用 - 数据共享
与其他测试⼯程师合作⼀起开发时,公共的模块要放在⼤家都访问到的地⽅。
使⽤ conftest.py 这个⽂件进⾏数据共享,并且他可以放在不同位置起着不同的范围共享作⽤。
前提:
执⾏:
步骤:
将登陆模块带@pytest.fixture 写在 conftest.py 里面
代码示例:
conftest.py
# conftest.py名字是固定的,不能改变
import pytest
@pytest.fixture(scope="function")
def login():
# setup操作
print('完成登录操作')
tocken = "abcdafafasdfds"
username = 'tom'
yield tocken, username # 相当于return
# teardown操作
print('完成登出操作')
test_test1.py
import pytest
'''
@pytest.fixture
def fixture_name():
setup 操作
yield 返回值
teardown 操作
'''
def test_search():
print('搜索')
# def test_cart():
# login()
# print('购物车')
def test_cart(login):
print('购物车')
def test_order(login):
print('下单功能')
class TestDemo:
def test_case1(self, login):
print("case1")
def test_case2(self, login):
print("case2")
项目结构:
9.pytest测试用例生命周期管理-自动生效
Fixture 在自动化中的应用 - 自动应用
场景:
不想原测试⽅法有任何改动,或全部都⾃动实现⾃动应⽤,
没特例,也都不需要返回值时可以选择⾃动应⽤
解决:
使⽤ fixture 中参数 autouse=True 实现
步骤:
在⽅法上⾯加 @pytest.fixture(autouse=True)
test_test1.py
import pytest
'''
@pytest.fixture
def fixture_name():
setup 操作
yield 返回值
teardown 操作
'''
def test_search():
print('搜索')
# def test_cart():
# login()
# print('购物车')
# def test_cart(login):
# print('购物车')
def test_cart():
print('购物车')
# def test_order(login):
# print('下单功能')
def test_order():
print('下单功能')
class TestDemo:
# def test_case1(self, login):
# print("case1")
def test_case1(self):
print("case1")
# def test_case2(self, login):
# print("case2")
def test_case2(self):
print("case2")
conftest.py
# conftest.py名字是固定的,不能改变
import pytest
@pytest.fixture(scope="function", autouse=True)
def login():
# setup操作
print('完成登录操作')
tocken = "abcdafafasdfds"
username = 'tom'
yield tocken, username # 相当于return
# teardown操作
print('完成登出操作')
运行结果:
10.pytestfixture实现参数化
Fixture 在自动化中的应用 -参数化
场景:
测试离不开数据,为了数据灵活,⼀般数据都是通过参数传的
解决:
fixture 通过固定参数 request 传递
步骤:
在 fixture 中增加@pytest.fixture(params=[1, 2, 3, ‘linda’])
在⽅法参数写 request,方法体里面使用 request.param 接收参数
# @pytest.fixture(params=['tom', 'jenny'])
# def login(request):
# print(f"用户名:{request.param}")
# return request.param
#
#
# def test_demo1(login):
# print(f'demo1 case:数据为{login}')
@pytest.fixture(params=[['tom', 'harry'], ['jenny', 'jack']])
def login(request):
print(f"用户名:{request.param}")
return request.param
def test_demo1(login):
print(f'demo1 case:数据为{login}')
Fixture 的用法总结