这些是之前的文章,里面有一些基础的知识点在前面由于前面已经有写过,所以这一篇就不再详细对之前的内容进行描述
Python自动化测试实战篇(1)读取xlsx中账户密码,unittest框架实现通过requests接口post登录网站请求,JSON判断登录是否成功
Python自动化测试实战篇(2)unittest实现批量接口测试,并用HTMLTestRunner输出测试报告
Python自动化测试实战篇(3)优化unittest批量自动化接口测试代码,ddt驱动+yaml实现用例调用,输出HTMLTestRunner测试报告
Python自动化测试实战篇(4)selenium+unttest+ddt实现自动化用例测试,模拟用户登陆点击交互测试,Assert捕获断言多种断言
Python自动化测试实战篇(5)优化selenium+unittest+ddt,搞定100条测试用例只执行前50条
Python自动化测试实战篇(6)用PO分层模式及思想,优化unittest+ddt+yaml+request登录接口自动化测试
Python自动化测试实战篇(7),初识pytest做一个简单的接口测试,allure输出可视化测试报告
Python自动化测试实战篇(8),pytest 测试用例初始化的五种方法与清洗方法
Python自动化测试实战篇(9),一口气学完pytest用例结构、测试框架结构、断言assert
Python自动化测试实战篇(10),一文吃透,Pytest 参数化与标记测试用例,测试用例失败重跑
pytest中常用框架就是setup和teardown为代表,pytest区别于这里面的功能,做到了更加简洁,而且在fixture中可以随意命名,没有固定格式之分,所以在pytest中使用selenium或者是appium将会变得更加简单快捷。
fixture只要被当成装饰器引用即可简单使用,不用再去考虑其他的框架结构,下面就是一个简单接口测试案例。
import pytest
import requests
url = "http://127.0.0.1"
payload={}
headers = {
'User-Agent': 'fox/1.0.0 ',
'Accept': '*/*',
'Host': '127.0.0.1:4523',
'Connection': 'keep-alive'
}
@pytest.fixture()
def login():
print("接口连接")
class TestFixture:
def test_case001(self, login):
response = requests.request("GET", url, headers=headers, data=payload)
assert response.status_code == 200
print("接口连接成功")
print(response.text)
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
其中有5个作用域
@pytest.fixture(scope='class')
def login():
print("接口连接")
class TestFixture:
def test_case001(self,login):
response = requests.request("GET", url, headers=headers, data=payload)
assert response.status_code == 200
print("接口连接成功")
print(response.text)
def test_case002(self,login):
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
@pytest.fixture(scope='class')
def login():
print("接口连接")
class TestFixture:
def test_case001(self,login):
response = requests.request("GET", url, headers=headers, data=payload)
assert response.status_code == 200
print("接口连接成功")
print(response.text)
def test_case002(self,login):
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
可以看到module会从每一个模块都执行一遍
@pytest.fixture(scope='package')
def login():
print("package:每个python包只执行一次")
class TestFixture:
def test_case001(self,login):
response = requests.request("GET", url, headers=headers, data=payload)
assert response.status_code == 200
print("接口连接成功")
print(response.text)
def test_case002(self,login):
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
def test_case003(self,login):
print("用例3")
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
@pytest.fixture(scope='session')
def login():
print("session:整个会话只执行一次,即运行项目时整个过程只执行一次")
class TestFixture:
def test_case001(self,login):
response = requests.request("GET", url, headers=headers, data=payload)
assert response.status_code == 200
print("接口连接成功")
print(response.text)
def test_case002(self,login):
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
def test_case003(self,login):
print("用例3")
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
fixture中5个参数分别是scope,params,autouse,ids和name。
scope:控制Fixture的作用范围
autouse:控制Fixture自动测试
ids:自定义fixture内参数内容
name:默认fixture函数名称
name参数也可以对fixture进行命名
params:指定Fixture的参数化内信息
用于起到代码进行分割,类似与setup和teardown作用,yield都可以进行返回值,用于返回作用
import pytest
@pytest.fixture(autouse=True)
def tx1():
print("开始")
yield 100
def test_e(tx1):
print("执行tx1")
print(tx1)
assert tx1 == 100
if __name__ == '__main__':
pytest.main(["-s","test3.py"])
import pytest
import requests
url = "http://127.0.0.1:4523/m1/2459729-0-default/registersearch?user=admin&password=123456"
payload={}
headers = {
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
'Accept': '*/*',
'Host': '127.0.0.1:4523',
'Connection': 'keep-alive'
}
@pytest.fixture(autouse=True)
def login():
response = requests.request("GET", url, headers=headers, data=payload)
yield response
print("清空数据")
class TestFixture:
def test_case001(self,login):
res = requests.request("GET", url, headers=headers, data=login)
assert res.status_code == 200
print("接口连接成功")
print(res.text)
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
import pytest
import requests
@pytest.fixture()
def test_1():
print("Testing1")
yield 1
print("Testing2")
@pytest.fixture()
def test_2(test_1):
print("执行test1")
yield 2
print("清除数据")
@pytest.fixture()
def fixture_add(test_1, test_2):
print("执行test1+test2")
result = test_1+test_2
yield result
print("Test")
def test_demo(fixture_add):
print("总和")
assert fixture_add ==3
if __name__ == '__main__':
pytest.main(["-s","test3.py"])
先执行test1,再执行test1+test2,最后全部总和
pytest中除了可以用yield和teardown作为执行用例的终结外还可用finalizer作为终结函数
直接对已经生成的数据进行终结
import pytest
import requests
url = "http://127.0.0.1:4523/m1/2459729-0-default/registersearch?user=admin&password=123456"
payload={}
headers = {
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
'Accept': '*/*',
'Host': '127.0.0.1:4523',
'Connection': 'keep-alive'
}
@pytest.fixture(autouse=True)
def login():
response = requests.request("GET", url, headers=headers, data=payload)
class TestFixture:
def test_case001(self,login):
res = requests.request("GET", url, headers=headers, data=login)
requests.addfinalizer(login)
assert res.status_code == 200
print("接口连接成功")
print(res.text)
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
执行终结之后就会发现数据已经被删掉,这一条测试用例执行错误。
可以对多个函数进行分批终结
import pytest
import requests
@pytest.fixture
def tx_first(request):
print("第一次执行")
# 定义终结函数
def tx1():
print("\n清除数据第一个")
def tx2():
print("\n清除数据第二个")
# 注册为终结函数
request.addfinalizer(tx1)
request.addfinalizer(tx2)
def test_2(tx_first):
print("\n执行tx1")
def test_1(tx_first):
print("\n执行tx2")
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
可以看到先从第二个开始执行然后再执行对一个,再多重终结中函数的执行顺序是倒序。
conftest.py用来单独存放fixture的文件,需要与用例的运行文件放在一起,如果希望共享这个文件则可以放在根目录下
conftest.py不需要import可以自动被pytest找到,可以将fixture都放在conftest中,把它当成fixture的仓库使用。
conftest也可以在测试函数执行前后执行连接数据库,打开文件,爬虫等操作。
创建一个conftest.py文件存在单独目录中与其他测试用例一起存放
conftest.py
import pytest
import requests
@pytest.fixture()
def into():
print("开始执行操作")
yield
print("结束")
test.py
import pytest
def test1(into):
print("执行conftest内的内的fixture内容")
if __name__ == '__main__':
pytest.main(["-vs", "test.py"])
运行后可以看到用例执行conftest.py中的fixture
autose默认为False,当它为True时可以自动调用里面的功能不用次次都去调用
import pytest
import requests
url = "http://127.0.0.1:4523/m1/2459729-0-default/registersearch?user=admin&password=123456"
payload={}
headers = {
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
'Accept': '*/*',
'Host': '127.0.0.1:4523',
'Connection': 'keep-alive'
}
@pytest.fixture(autouse=True)
def login(request):
response = requests.request("GET", url, headers=headers, data=payload)
print(response.text)
yield
print("测试结束")
class TestFixture:
def test_case001(self,login):
res = requests.request("GET", url, headers=headers, data=login)
assert res.status_code == 200
print("接口连接成功")
print(res.text)
def test_case002(request):
print(request)
print("测试用例2")
if __name__ == '__main__':
pytest.main(["-vs", "test3.py"])
如下所示test_case002直接调用login中的功能,每个用例都可以自动调用,自动进行使用,而不用重复去写功能。当然autose也可以和其他的fixture混合使用