Pytest相关
简介:pytest比unittest框架更简洁,效率更高。
特点:
- pytest直接使用python内置的assert语句进行断言
- pytest能够自动识别测试模块和测试函数
- pytest框架中最核心的模块就是fixtures模块,其能够实现对象、参数化、用例等一系列的管理操作
- 能够兼容unittest框架、nose框架等测试套件的运行
- pytest具有丰富的插件
安装:pip install pytest
查看版本:pip show pytest 或 pytest --version
定义测试用例
函数实现定义测试用例
【例】现有一个源码类计算器,该类实现了加法运算
SourceDir/Calulater
class Cal(object):
def add(self,a,b):
return a+b
TestDir/TestCalulater
from InterFaceTest.Day04.SourceDir.Calulater import Cal
import pytest
#声明一个函数测试用例
def test_add():
cal=Cal()
assert 4==cal.add(2,2) #python中所存在的assert语句
#使用类似于unittest框架调用main方法的形式进行执行那个测试函数
if __name__ == '__main__':
pytest.main()
然后在pychram中运行会显示如下图所示的情况,说明当前模块将以pytest框架运行:
如果仅仅还是run Calulater的话那么说明还是以python运行器运行,则需要修改相关设置操作:
修改上面的运行器后,如果还无法识别为pytest运行的话,那么考虑模块名是否以Test开头或者可以通过configuration进行配置pytest运行;测试用例的方法名还是需要以test开头。
pytest运行规则:查找当前目录及其子目录下以test_*.py或*_test.py文件,找到文件后,在文件中找到以test开头函数并执行。
类实现定义测试用例
from InterFaceTest.Day04.SourceDir.Calulater import Cal
import pytest
#如果声明测试类进行设计测试用例的话,那么测试类的名字必须以Test开头
class TestCal():
def test_add(self):
cal = Cal()
assert 4 == cal.add(2, 2)
if __name__ == '__main__':
pytest.main()
Dos中运行方式
- a.pytest 测试文件所在路径
- b.py.test 测试文件所在路径
- c.python -m pytest 测试文件所在路径
如果提示不是内部或者外部命令或者提示找不到对应模块pytest,则说明当前python环境中没有pytest模块或者没有配置环境变量,需要检查。
有同学肯定会有疑惑,有了pycharm运行方式为什么还要dos命令的运行方式?如果有此疑惑的同学,说明大家引用持续集成不够多呀,持续集成都需要引用命令的形式完成操作的。
节点执行
如果一个测试模块中声明的测试类中存在多个测试方法的话,那么在pycharm中可以选中那个测试方法运行那么说明指定当前的测试方法运行,如果将光标处于main方法中则执行所有的测试用例,这样可以通过光标的位置决定执行哪个测试用例。
但是,在dos中那么如何指定某个测试方法进行执行呢?这就可以通过其pytest中的节点设置完成,我们先来分析pycharm中如果选择某一个测试方法执行结果:
通过上图可以发现选择某一个测试用例执行的方式,所以在dos中就可以如下方式执行:
Pytest断言
断言是写自动化测试基本最重要的一步,一个用例没有断言,就失去了自动化测试的意义了。什么是断言呢?
简单来讲就是实际结果和期望结果去对比,符合预期那就测试pass,不符合预期那就测试 failed。
常用断言
pytest里面断言实际上就是python里面的assert断言方法,常用的有以下几种:
- assert xx 判断xx为真
- assert not xx 判断xx不为真
- assert a in b 判断b包含a
- assert a == b 判断a等于b
- assert a != b 判断a不等于b
import pytest
class Test_Assert():
def test_assert_1(self):
assert 1
def test_assert_2(self):
assert [1,2,3]==[1,2,3]
def test_assert_3(self):
assert 1 in [1,2,3]
def test_assert_4(self):
assert 20 not in [10,30,40]
if __name__ == '__main__':
pytest.main()
执行结果:
异常断言
假设现在将接口的服务进行关闭,且完成接口请求的发送,那么此时会抛出异常requests.exceptions.ConnectionError,此时如果需要断言该异常
传统型的异常断言方式
def test_add_customer_lost_name(self):
data=data={
"customer_phone": "18907047890",
"customer_mail": "fjwojefo@163.com",
"customer_type": "C",
"customer_address": "广州天河"
}
expect={'reason': '缺少客户名称参数', 'result': [], 'error_code': 2014}
try:
get_actual=requests.post("http://127.0.0.1:7777/addCustomer",data=data).json()
#就要断言异常
assert get_actual==expect
except(requests.exceptions.ConnectionError) as e:
get_result=sys.exc_info()
print(get_result[0]) #type 是一个类,不是一个对象实例
print(get_result[1]) #message
#assert requests.exceptions.Cnotallow==Exception #类型必须完全一致,不存在父子继承关系比较
#assert requests.exceptions.ConnectionError is get_result[0] #表示的是两个对象地址是相同的
#myExceptinotallow=Exception()
#assert isinstance(e,(Exception,)) #此种情况就可以完成父子关系的实例断言操作
通过pytest.raises作为上下文管理器
#pytest实现异常断言
def test_add_customer_lost_name_1(self):
data = data = {
"customer_phone": "18907047890",
"customer_mail": "fjwojefo@163.com",
"customer_type": "C",
"customer_address": "广州天河"
}
with pytest.raises(Exception) as ec: #表示的是下面代码抛出的异常类型是否与指定的异常类型一致
get_actual = requests.post("http://127.0.0.1:7777/addCustomer", data=data).json()
print(ec.value)
print(ec.type)
print(ec.traceback)