Pytest框架简易教程

一、Pytest简介

测试框架是用来组织测试用例并进行运行控制的。使用框架可以做到:

  • 挑选用例并批量执行
  • 单条用例失败后不影响其他用例执行
  • 不同范围的测试准备和环境清理方法
  • 一套断言机制
  • 运行完生成测试报告

二、用例编写和断言

  • 函数式写法
# test_demo1.py
import requests
def test_1():
    assert 1+1 >= 2

def test_2():
    res = requests.get('https:/xxxxxx.com')
    assert res.status_code == 200

*注意:测试脚本,测试函数名都要以test开头

  • 类式写法
 import requests
class TestDem2(object):
    base_url = 'http://add/'    
    def test_add1():
        res = requests.get(self.url, params = {'a':1,'b':2})
        assert res.text == 3 
    def test_add2():
         res = requests.get(self.url, params = {'a':-1,'b':2})
        assert res.text == 1

注意:

  1. 测试脚本,测试函数名都要以test开头, 类名以Test开头
  2. 测试类不需要继承unittest.TestCase, 测试类中不能有__init__方法
  • 断言相等
assert 1+1 == 2
assert 1+2 != 2
assert 5 >= 4
assert {'a': 1, 'b': 2} == {'b':2, 'a':1}  # 也可用例判断列表和字典相等
  • 断言包含
assert '百度' in driver.title
assert 1 in [1,2,3]
  • 断言True/False/None
assert 3>2 is True
assert 3>2 is not False
assert [] is not None

注意:1.is和==的不同,为值相等,is必须内存地址相同(是同一个对象)1True
但 1 is not True。
2.Python中[],{},(),0,‘0’,’'都被视为假,因此可以用assert list1来判断list1不为空。

用例运行

  1. 命令行运行
    打开命令行,进入脚本所在目录,执行pytest test_demo1.py
    注:如果不在脚本所在目录需加上脚本路径,如:pytest D:/test_demo1.py
  2. 在脚本中调用执行
if __name__ == '__main__':
    pytest.main(["test_demo1.py"])
  • 常用执行参数
    1.-v: 详细显示模式(否则执行通过的用例只显示一个点)
    2.-q: 安静模式,不显示环境信息
    3.-s: 命令行显示print输出而不是捕获并输出到报告中

测试准备与环境清理

  • 一般来说,每条用例都需要一定的预置条件或数据准备。而如果用例执行了修改操作或产生了新的数据,还应该对环境进行还原和清理。在测试框架中,这种准备方法叫做setup,清理方法叫做teardown,这两种方法统称为Test Fixtures(夹具),像一个夹子一样把用例夹在中间。
  • 这种Test Fixtures是有一定范围的。可以每次只夹一条用例(相当于每条用例都先执行setup方法,执行完用例再执行teardown方法),也在一批用例执行前执行一次setup,都执行完再执行teardown。
  • Pytest中的Test Fixtures方法有5种范围:
    1.Session会话级:运行一次Pytest算一次会话。运行期间只setup/teardown一次
    2.Package包级:对每个包Python包setup/teardown一次
    3.Module模块级:对每个Python脚本setup/teardwon一次
    4.Class级:对每个测试类setup/teardown一次
    5.Function级/Method级:对每个测试函数、测试方法setup/teardown一次

内置的模块/类/函数/方法级别的Fixtures

  • setup_module()/teardown_module()
  • setup_class()/teardown_class()
  • setup_function()/teardown_function()
  • setup_method()/teardown_method()

session > module > class > function执行顺序

自定义Fixtures方法

用于以下场景

  1. 自定义级别的测试准备和环境清理方法,如会话级,包级
  2. 全局变量,如浏览器driver,数据库连接,用例数据等
  3. 测试辅助步骤,如获取token,登录步骤等
import pytest
@pytest.fixture
def my():
    print("setup ...")
    yield 123
    print('teardown')

@pytest.fixture(scope='session', autouse=True)
def my2():
    print('my2 setup ...')

注:如果不需要清理方法,yield也可以使用return返回,如果setup出错,用例及teardown则不会执行。

自定义Fixtures方法的使用

Fixtures方法可以通过注入方式注入到用例中使用,Fixture方法之间也可以相互注入。Fixtures方的主要使用方式有3种:

  1. Fixture方法名直接作为用例参数使用(可以拿到fixture方法返回值)
  2. 使用@pytest.userfixtures()
  3. 自动使用,fixture方法设置了autouse=True
import pytest
@pytest.mark.usefixtures('my')
def test_a():
    print('test_a')
def test_b(my):  # fixture方面名直接作为参数使用
    print("test_b")
    print(my)
def test_c():
    print("test_c")

输出:

collected 3 items                                                                                                                                                                       

test_aaa.py::test_a my2 setup ...
setup ...
test_a
PASSEDteardown

test_aaa.py::test_b setup ...
test_b
123
PASSEDteardown

test_aaa.py::test_c test_c
PASSED

Fixtures方法共享、范围及优先级

Fixtures方法一般作为公用的辅助方法或全局变量来使用,因此需要在不同用例中都能使用。一般我们用conftest.py这个文件来集中管理Fixtures方法。
生效范围:对conftest.py所在目录及子目录下的所有用例生效。
优先级:用例就近原则。用例文件中的Fixtures方法>当前目录conftest.py中的Fixtures方法>上级目录conftest.py中的Fixtures方法>…
因此,在项目不同模块中使用conftest.py可以实现不同级别的测试准备、清理或辅助方法,如:
目录

数据驱动

在测试用例中,数据的丰富性是非常重要的。同一个测试流程往往需要测试多组数据。我们并不需要把用例复制很多遍然后改为不同的数据。只需要使用数据驱动即可。首先我们需要一个模板,如测试加法接口:

import requests
def test_add():
   res = requests.get('/add/?a=1&b=2')
   assert res.text == '3'

假如我们要验证1+2=3,-1+2=-1,1.5+2.5=4这三组数据。

  1. 我们将这三个数据参数化成a,b,sum,通过参数传入用例,如下:
def test_add(a,b,sum):  # 需要传入a,b,sum三个参数
   res = requests.get(f'add/?a={a}&b={b}')
   assert res.text == sum
  1. 我们把每一组放到一个列表中作为一组数据,那么这三组数据为:
data = [[1, 2, 3], [-1, 2, -1] ,[1.5, 2.5, 4]]
  1. 使用@pytest.mark.parametrize(‘a, b, sum’, data) 将数据分批注入用例,我们需要将data中的三个参数映射给用例参数a,b,sum,因此parametrize中的’a,b,sum’要与用例参数一致。和子列表中的数据个数一致。

完整代码如下:

import requests
import pytest
data = [[1, 2, 3], [-1, 2, 1] 
@pytest.mark.parametrize('a, b, sum', data)
def test_add(a,b,sum):  # 需要传入a,b,sum三个参数
   res = requests.get(f'/add/?a={a}&b={b}')
   assert res.text == str(sum)

输出:

plugins: base-url-1.4.1, check-0.3.5, html-1.22.0, metadata-1.8.0
collected 2 items                                                                                                                                                                       

test_aaa.py::test_add[1-2-3] PASSED
test_aaa.py::test_add[-1-2-1] PASSED

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值