一文让你快速入门pytest框架

pytest是什么

官方文档描述:

pytest is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.

pytest是一个python单元测试框架。

pytest的特点

pytest与unitest区别

pytest用例执行

  • 使用pytest.main方法执行
import pytest

def func(x):
    return x+1

def test_b():
    print('-----test_b-----')
    assert func(3)==5  # 断言失败

def test_a():
    print('-----test_a-----')
    assert func(3)==4   # 断言成功

if __name__=="__main__":
    pytest.main(['-s','test_demo.py'])
  • 使用命令行执行

执行单个文件,进入到文件所在路径
pytest -s test_demo.py

执行整个目录
pytest -s 目录名称

pytest常用命令参数

  • 参数:-s
    运行过程中执行print打印函数:pytest -s

  • 参数:-v 或 -q
    打印用例执行的详细/简略过程,pytest -v ,pytest -q

参考:https://www.cnblogs.com/sc912/p/11369237.html

pytest用例前置和后置

setup、teardown,在方法前后执行

  • pytest的setup、teardown方法可以在类之外
import pytest


def test_a():
    print('-----test_a-----')

def test_b():
    print('-----test_b-----')

def setup():
    print('-----setup-----')

def teardown():
    print('-----teardown----')

if __name__ == '__main__':
    if __name__ == '__main__':
        pytest.main(['-s','test_method.py'])

执行结果如下:

-----setup-----
PASSED                                            [ 50%]-----test_a-----
-----teardown----

test_method.py::test_b -----setup-----
PASSED                                            [100%]-----test_b-----
-----teardown----
  • pytest的setup、teardown方法放在类之内
import pytest

class Test_method():
    def test_a(self):
        print('-----test_a-----')

    def test_b(self):
        print('-----test_b-----')

    def setup(self):
        print('-----setup-----')

    def teardown(self):
        print('-----teardown----')

if __name__ == '__main__':
    if __name__ == '__main__':
        pytest.main(['-s','test_method.py'])

执行结果如下:

test_method.py::Test_method::test_b 

============================== 2 passed in 0.02s ==============================
Process finished with exit code 0
-----setup-----
PASSED                               [ 50%]-----test_a-----
-----teardown----
-----setup-----
PASSED                               [100%]-----test_b-----
-----teardown----

可以看到,在执行每一个方法前都会执行setup方法,在执行每个方法后都会执行teardown方法。

setup_class、teardown_class,在类前后执行

setup_class、teardown_class方法得放在类里面,否则不生效。

import pytest


class TestMethod():
    def test_a(self):
        print('-----test_a-----')

    def test_b(self):
        print('-----test_b-----')

    def setup_class(self):
        print('-----setup-----')

    def teardown_class(self):
        print('-----teardown----')

if __name__ == '__main__':
    if __name__ == '__main__':
        pytest.main(['-s','test_class.py'])

执行结果如下:

test_class.py::TestMethod::test_a -----setup-----
PASSED                                 [ 50%]-----test_a-----

test_class.py::TestMethod::test_b PASSED                                 [100%]-----test_b-----
-----teardown----

可以看出,先执行一次setup_class,然后执行完全部方法,再执行teardown_class方法。

import pytest


class TestMethod():
    def test_a(self):
        print('-----test_a-----')

    def test_b(self):
        print('-----test_b-----')

    def setup(self):
        print('-----setup-----')

    def teardown(self):
        print('-----teardown----')

    def setup_class(self):
        print('-----setup_class-----')

    def teardown_class(self):
        print('-----teardown_class----')

if __name__ == '__main__':
    if __name__ == '__main__':
        pytest.main(['-s','test_class.py'])

执行结果如下:

test_class.py::TestMethod::test_a -----setup_class-----
-----setup-----
PASSED                                 [ 50%]-----test_a-----
-----teardown----

test_class.py::TestMethod::test_b -----setup-----
PASSED                                 [100%]-----test_b-----
-----teardown----
-----teardown_class----

pytest运行规则

默认规则

自定义规则

使用配置文件pytest.ini进行配置

安装ini插件

pycharm无法识别ini文件,需要安装插件。

配置文件在test_pytest目录下

指定执行test_ini目录的测试用例
(venv) D:Testpythonhogwarts_TD est_pytest>pytest -v

执行结果如下:

test_ini/test_class.py::TestMethod::test_a -----setup_class-----
-----setup-----
-----test_a-----
PASSED-----teardown----

test_ini/test_class.py::TestMethod::test_b -----setup-----
-----test_b-----
PASSED-----teardown----
-----teardown_class----

注释掉指定目录后,是执行10个用例

pytest断言

from common.get_mysql import *

def test_assert():
    a=0
    b=1
    # assert a,'断言失败打印的信息'  # 自定义断言失败打印的信息,用逗号隔开
    assert not a,'断言失败打印的信息'
    assert b,'断言失败打印的信息'
    c='c'
    d='adacde'
    e='aeewd'
    assert c in d,'断言失败打印的信息'
    assert c not in e,'断言失败打印的信息'
    
    assert a!=b
    assert a==b
    # 对比数据库数据
    assert a==get_sql("SELECT dept_no FROM departments WHERE dept_name ='Finance'")

pytest标记

是pytest特有的机制,unitest没有,作用是筛选用例。

标记测试用例

遇到问题:

执行后
(venv) D:Testpythonhogwarts_TD est_pytest>pytest -m testa

警告:
PytestUnknownMarkWarning: Unknown pytest.mark.testa - is this a typo?

怎么是执行了两条用例?应该是执行一条用例才对

似乎是与配置文件有关。

(venv) D:Testpythonhogwarts_TD est_pytest>pytest -m "testa or testb"

跳过测试、条件判断执行

import pytest


class TestMethod():
    @pytest.mark.skip
    def test_a(self):
        print('-----test_a-----')

    # 只执行test_b
    def test_b(self):
        print('-----test_b-----')


if __name__ == '__main__':
    pytest.main(['-s','test_mark.py'])

全部用例都不执行

import pytest

@pytest.mark.skip(reason="不要执行的用例")  # reason可以不写
class TestMethod():

    def test_a(self):
        print('-----test_a-----')


    def test_b(self):
        print('-----test_b-----')


if __name__ == '__main__':
    pytest.main(['-s','test_mark.py'])

为真的时候不执行

import pytest


class TestMethod():
    @pytest.mark.skip(reason="不要执行的用例")  # reason可以不写
    def test_a(self):
        print('-----test_a-----')

    @pytest.mark.skipif(2>1,reason="不要执行的用例")  # 为真的时候不执行
    def test_b(self):
        print('-----test_b-----')


if __name__ == '__main__':
    pytest.main(['-s','test_mark.py'])

为假的时候执行用例

import pytest


class TestMethod():
    @pytest.mark.skip(reason="不要执行的用例")  # reason可以不写
    def test_a(self):
        print('-----test_a-----')

    @pytest.mark.skipif(0>1,reason="不要执行的用例")
    def test_b(self):
        print('-----test_b-----')


if __name__ == '__main__':
    pytest.main(['-s','test_mark.py'])

pytest参数化

传入单个参数

在测试用例的前面加上:
@pytest.mark.parametrize("参数名",列表数据)
参数名:用来接收每一项数据,并作为测试用例的参数。
列表数据:一组测试数据。

import pytest


class TestMethod():
    @pytest.mark.parametrize('name',['xiaoming','jack'])
    def test_a(self,name):
        print('-----test_a-----')
        print(name)

    @pytest.mark.parametrize(('username','password'),[('xiaoming','123456'),('jacky','567890')])
    def test_b(self,username,password):
        print('-----test_b-----')
        print('username: "{}",password:"{}"'.format(username,password))


if __name__ == '__main__':
    pytest.main(['-s','test_para.py'])

执行结果:

============================== 4 passed in 0.02s ==============================
Process finished with exit code 0
PASSED                        [ 25%]-----test_a-----
xiaoming
PASSED                            [ 50%]-----test_a-----
jack
PASSED                 [ 75%]-----test_b-----
username: "xiaoming",password:"123456"
PASSED                    [100%]-----test_b-----
username: "jacky",password:"567890"

传入多个参数

传入文件参数

pytest生成报告

修改配置文件

以下是html报告

pytest执行失败重试

修改配置文件

reruns 2,表示失败时重试2次
delay 1,表示等待1s

原文地址:https://www.cnblogs.com/Uni-Hoang/p/13290679.html