Pytest

pytest 6.0.2

一、Pytest运行方式

测试类主函数模式

import pytest

if __name__ == "__main__":
    pytest.main()
    #自动搜寻所有目录下的适合文件并执行
    pytest.main(['./scripts/test_01.py','./scripts/test_02.py'])
    #指定测试文件

命令行运行

pytest
#自动搜寻所有目录下的适合文件并执行
pytest ./scripts/test_01.py
#指定文件执行

二、pytest.init

pytest.ini 可以修改 pytest 的默认行为

注意: pytest.ini 不能使用任何中文符号,包括汉字、空格、引号、冒号等等;

[pytest]
addopts = --alluredir=reports
#更改默认命令行参数
testpaths = test_path
#指定测试目录
norecursedirs = .* build dist CVS _darcs {arch} *.egg venv old-src
#指定 pytest 忽略某些目录
python_files =     test_*  *_test  check_*
python_classes =   Test*   Check*
python_functions = test_*  check_*
#更改测试用例收集规则:
#pytest 默认的用例收集规则:
#测试模块必须以 test_ 开头或以 _test 结尾;
#测试类必须以 Test 开头,且不能有 __init__() ;
#测试方法必须以 test_ 开头;
xfail_strict = true
#禁用 XPASS 将标记为 @pytest.mark.xfail 但实际通过的测试用例报告为失败

三、Pytest的setup和teardown函数

函数级别setup()/teardown()运行于测试方法的始末,即:运行一次测试函数会运行一次setup和teardown

import pytest
class Test_01(object):
    def setup():
        print('setup')
    def teardown():
        print('teardown')

类级别setup_class()/teardown_class()运行于测试类的始末,即:在一个测试内只运行一次setup_class和teardown_class,不关心测试类内有多少个测试函数

import pytest
class Test_01(object):
    def setup_class():
        print('setup_class')
    def teardown_class():
        print('teardown_class')

四、Pytest fixture

fixture修饰器来标记固定的工厂函数,在其他函数,模块,类或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作

#简单例子
class Test_ABC:
    @pytest.fixture()
    def before(self):
        print("------->before")
    def test_a(self,before): # ️ test_a方法传入了被fixture标识的函数,已变量的形式
        print("------->test_a")
        assert 1
if __name__ == '__main__':
    pytest.main("-s  test_abc.py")
执行结果:
    test_abc.py 
        ------->before # 发现before会优先于测试函数运行
        ------->test_a
         .

五、Pytest断言

assert 1
assert 0
assert a == b

六、Pytest参数化

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

#单个参数时
@pytest.mark.parametrize('passwd',['123456','abcdefdfs','as52345fasdf4'])
def test_passwd_length(passwd):
    assert len(passwd) >= 8

#多个参数时
@pytest.mark.parametrize('user, passwd',[('jack', 'abcdefgh'),('tom', 'a123456a')])
def test_passwd_md5(user, passwd):
    db = {
        'jack': 'e8dc4081b13434b45189a720b77b6818',
        'tom': '1702a132e769a623c1adb78353fc9503'
    }
    import hashlib
    assert hashlib.md5(passwd.encode()).hexdigest() == db[user]

七、Pytest跳过测试

Pytest 使用特定的标记 pytest.mark.skip 跳过测试

Pytest 还支持使用 pytest.mark.skipif 为测试函数指定被忽略的条件

@pytest.mark.skip()
def test_A():
    pass
@pytest.mark.skip(reason="xxx")
def test_B():
    pass
方法:
     skipif(condition, reason=None)
 参数:
     condition:跳过的条件,必传参数
     reason:标注原因,必传参数
 使用方法:
     @pytest.mark.skipif(condition, reason="xxx")

@pytest.mark.skipif(condition,reason='XXX')
def test_A():
    pass

八、Python预见的错误

如果我们事先知道测试函数会执行失败,但又不想直接跳过,而是希望显示的提示。

Pytest 使用 pytest.mark.xfail 实现预见错误功能:

@pytest.mark.xfail(condition,reason='XXX')
def test_A():
    assert 1 == 1

九、Pytest捕获异常

在测试过程中,经常需要测试是否如期抛出预期的异常,以确定异常处理模块生效。在 pytest 中使用 pytest.raises() 进行异常捕获:

import pytest

def test_raises():
    with pytest.raises(TypeError) as e:
        connect('localhost', '6379')
    exec_msg = e.value.args[0]
    assert exec_msg == 'port type must be int'

声明:该文章系转载,转载该文章的目的在于更广泛的传递信息,并不代表本网站赞同其观点,文章内容仅供参考。

本站是一个个人学习和交流平台,网站上部分文章为网站管理员和网友从相关媒体转载而来,并不用于任何商业目的,内容为作者个人观点, 并不代表本网站赞同其观点和对其真实性负责。

我们已经尽可能的对作者和来源进行了通告,但是可能由于能力有限或疏忽,导致作者和来源有误,亦可能您并不期望您的作品在我们的网站上发布。我们为这些问题向您致歉,如果您在我站上发现此类问题,请及时联系我们,我们将根据您的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。