pytest+allure

知识点1:

1、测试结果信息阅读

  • passed表示通过,有个简写.

  • failed表示失败,有个简写F

2、命令行参数

  • -h:帮助

  • -version:版本信息

3、测试用例命名规则:

  • 测试函数必须以test开头

  • 测试类必须以Test开头,但测试类不能有init方法

  • 测试文件必须以test/Test开头,或者test/Test结尾

4、运行指定的测试用例:指定文件[::类名][::函数名]

  • 用例搜索的规则默认是pytest执行当前目录及子目录(遍历)

  • 指定类名运行:pytest 文件名::类名

  • 指定函数名运行:pytest 文件名::类名::函数名

  • 指定函数名运行:pytest 文件名::函数名

  • 指定目录下的文件运行:pytest 目录名\文件名::函数名

  • pytest .\test_a02\test_a02_a.py::test_001 (test_a02_a.py文件下的test_001 类;终端)

5、pytest.main()执行用例

  • 命令行参数args,列表类型,一个或多个str组成,逗号分隔
import pytest


def test_a01():
    assert 1 == 1


if __name__ == '__main__':  # 运行测试的话,需要在pycharm中设置python集成工具=>unittest
    # pytest.main()  # 等价于pytest命令
    # pytest.main([__file__])  # 测试当前文件
    # pytest.main(['--version'])
    pytest.main['-sv', __file__]  # 多参数调用

6、运行指定测试用例——k参数

  • 匹配测试类或测试方法的名字部分

  • 大小写敏感

  • 逻辑运算

表达式 说明
-k login 测试类名或函数名中包含login的用例
-k not login 不包含login的
-k login and success 包含login且包含success的
-k login or success 包含login或success的
-k login and not success 包含login且不包含success的
import pytest


def test_login_success():
    pass


def test_login_failed():
    pass


def test_logout_success():
    pass


def test_logout_failed():
    pass


if __name__ == '__main__':
    pytest.main(['-k success and not failed', '--collect-only', __file__])  # –collect-only 含义:展示给定配置下哪些测试用例会被运行

pytest+allure_第1张图片

7、pytest.mark.skip/skipif

  • 有条件的忽略skipif
import pytest, sys


@pytest.mark.skipif(1 == 1, reason='if 1==1 skip this')  # 条件满足就忽略测试  reason:标注原因
def test_a01_1(reason='i wanna skip this case'):
    pass


@pytest.mark.skipif(1 == 2, reason='if 1==2 skip this')  # 条件不满足不会跳过
def test_a01_2():
    pass


@pytest.mark.skipif(sys.platform == 'linux', reason='if linux skip this')  # sys.platform 操作系统平台标识
def test_a01_3():
    pass


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第2张图片

  • 输出结果s
import pytest


@pytest.mark.skip
def test_a01_1(reason='i wanna skip this case'):
    pass


def test_a01_2():
    pass


if __name__ == '__main__':
    pytest.main(['-sv', __file__])
    # pytest.main(['--collect-only', __file__])  # 能被采集
    # pytest.main([__file__])  # 输出s

pytest+allure_第3张图片

import pytest

pytestmark = pytest.mark.skip('skip all cases')  # pytestmark 这个名字不可更改


def test_a01_1():
    pass


def test_a01_2():
    pass


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第4张图片

import pytest


def test_a01_1():
    arrow = pytest.importorskip('arrow')  # 这个库在当前环境下没有的话会报错,有会自动导入
    nowtime = arrow.now().format('YYYY-MM-DD')  # 获取当前时间
    print(nowtime)


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第5张图片

8、pytest.mark.parameterize参数化

  • 当对一个测试函数进行测试时,通常会给函数传递多组参数。比如测试账号登录,我们需要模拟各种千奇百怪的账号密码。当然,我们可以把这些参数写在测试函数内部进行遍历。不过虽然参数众多,但仍然是一个测试,当某组参数导致断言失败,测试也就终止了。通过异常捕获,我们可以保证所有参数完整执行,但要分析测试结果就需要做不少额外的工作

  • 在pytest中,我们有更好的解决方法,就是参数化测试,即每组参数都独立执行一次测试。使用的工具就是 pytest.mark.parametrize(argnames, argvalues)

  • 分析parameterize的源码,能看到调用时要用到的参数

参数 含义
argnames 必选,参数名,逗号分隔的字符串,表示一个或多个参数名字,也可以是字符串组成的列表或元组
argvalues 必选,参数值列表
indirect 为True时,argnames一定是一个fixture的函数名称,argvalues的值传入对应的fixture内,相当于@pytest.fixture(params=)的做法,默认为False
ids 用例id,标记子用例执行名称,与argvalues数量一致,未指定则自动生成,默认为None
scope 作用范围,类似于fixture中的scope参数,表示参数的范围,范围用于按参数实例对测试进行分组。它将覆盖任何fixture函数定义的范围,允许使用测试上下文或配置设置动态范围

参数匹配,argnames跟测试函数的参数必须一致否则会报错

import pytest


@pytest.mark.parametrize('arg0', [0, 1])  # (0, 1)   '01' 不推荐用
def test_a01_1(arg0):
    print(arg0)


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第6张图片

多个参数

import pytest


@pytest.mark.parametrize('arg0, arg1', [(0, 1), (2, 2), (3, 4)])  # argvalues 往往是通过其他程序读取到
def test_a01_1(arg0, arg1):
    print(f'arg0 is {arg0},arg1 is {arg1}')
    assert arg0 == arg1


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第7张图片

多个装饰器

import pytest


@pytest.mark.parametrize('arg0', [1, 2, 3])  # 多装饰器 笛卡尔积的效果 两两相乘
@pytest.mark.parametrize('arg1', [4, 5, 6])
def test_a01_1(arg0, arg1):
    print(f'arg0 is {arg0},arg1 is {arg1}')


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第8张图片

ids参数的作用

import pytest


def login(username, password):
    data = {'allen': '12', 'smith': '34', 'ford': '56'}
    if data.get(username) == password:
        return 'success'
    else:
        return 'failed'


@pytest.mark.parametrize('username, password, expect', [('allen', '12', 'success'), ('smith', '344', 'failed')],
                         ids=['login success', 'login failed'])
def test_a01_1(username, password, expect):
    assert login(username, password) == expect


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第9张图片

9、setup和teardown(不常用,有更好的)

  • setup往往指测试用例中的配置部分(预置条件),teardown则对应销毁部分(环境拆除)

  • PyTest支持xUnit style结构,setup()和teardown()方法用于初始化和清理测试环境,可以保证测试用例的独立性

方法 作用域 说明
setup_function/teardown_function 函数function 每个函数都使用一次(类中的函数叫方法不记在内)
setup_class/teardown_class 类class 需要在类中定义,一个类运行一次
setup_module/teardown_function 模块(一个py文件) 一个模块运行一次
setup_method/teardown_method 方法(类中函数) 一个方法运行一次
setup/teardown 方法(类中函数) 一个方法运行一次
import pytest


def setup_function():
    print('\n函数前执行 setup')

    
def teardown_function():
    print('\n函数后执行 teardown')


def test_a01_1():
    pass


def test_a01_2():
    pass


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第10张图片

import pytest


class Test_all():
    def setup_class(self):
        print('\n方法前执行 setup')

    def teardown_class(self):
        print('\n方法后执行 teardown')

    def test_a01_1(self):  # method 方法不叫函数
        pass

    def test_a01_2(self):
        pass


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第11张图片

import pytest


def test_a01_3():
    pass


def setup_module():
    print('\n模块前执行 setup')


def teardown_module():
    print('\n模块后执行 teardown')


class Test_all():
    def test_a01_1(self):  # method 方法不叫函数
        pass

    def test_a01_2(self):
        pass


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

pytest+allure_第12张图片

import pytest


class Test_all():
    def setup_method(self):
        print('\n方法前执行 setup01')

    def teardown_method(self):
        print('\n方法后执行 teardown01')

    def setup(self):
        print('\n方法前执行 setup02')

    def teardown(self):
        print('\n方法后执行 teardown02')

    def test_a01_1(self):  # method 方法不叫函数
        pass

    def test_a01_2(self):
        pass


if __name__ == '__main__':
    pytest.main(['-sv', __file__])

10、pytest-base-url插件

import pytest, requests


def test_a01_1(base_url):  # 当作为fixture使用的时候是base_url,安装的是pytest-base-url
    resp = requests.get(base_url)
    assert resp.status_code == 200


if __name__ == '__main__':
    pytest.main(['-sv', '--base-url', 'https://www.baidu.com', __file__])
    # pytest.main(['-sv', __file__])  # 使用配置文件执行,本级目录下新建pytest.init文件,新增一行 base_url = https://www.baidu.com

pytest+allure_第13张图片

11、pytest-repeat插件

import pytest


@pytest.mark.repeat(3)
def test_a01_1():
    print('01 testing')
    assert 1 == 1


if __name__ == '__main__':
    pytest.main(['-sv', __file__])
import pytest


def test_a01_1():
    print('01 testing')
    assert 1 == 1


if __name__ == '__main__':
    pytest.main(['-sv','--count=3', __file__])

pytest+allure_第14张图片

import pytest


def test_a01_A1():
    print('A1 testing')
    assert True


def test_a01_A2():
    print('A2 testing')
    assert True


def test_a01_B1():
    print('B1 testing')
    assert True


def test_a01_B2():
    print('B2 testing')
    assert True


if __name__ == '__main__':
    pytest.main(['-sv', '--count=2', '--repeat-scope=session', __file__])  # session/module/class都是1212的顺序

pytest+allure_第15张图片

12、allure生成报告

你可能感兴趣的:(pytest,python)