自动化测试之Pytest入门


pytest是一个功能非常全面的Python自动化测试框架

特点:

1、简单灵活,支持参数化,可以细粒度的控制测试用例;

2、不仅支持简单的单元测试,还支持复杂的功能测试,不仅可以用来做selenium/appium的UI自动化测试,还可以用作做基于Python+requests的接口自动化测试;

3、第三方插件非常丰富,如pytest-selenium(集成了selenium)、pytest-html(完美的html测试报告)、pytest-reunfailures(失败case重复测试)等;

4、测试用例跳跃式(skip)执行以及标记后选择性处理(mark);

5、很好的与CI工具(jenkins)结合;

 

编写规则:

1、测试文件以test_开头,以_test结尾也可以;

2、测试类以Test开头,并且不能带有__init__方法;

3、测试函数(方法)以test_开头;

4、断言使用assert;

 

一、安装pytest

$ pip install pytest

二、执行一个测试

测试通过

# test_demo8.py

def test_pass():
    assert 1 == 1

通过pytest来运行上面测试函数

在pycharm的Terminal中直接输入命令pytest test_demo8.py执行

MacBook-Pro:test_demo fyuanyuan$ pytest test_demo8.py

========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 1 item

test_demo8.py . [100%]

========================================================================================== 1 passed in 0.01s ===========================================================================================

执行结果为test_demo8.py测试通过(pytest使用 . 标识测试通过PASSED)

下面使用-v选项来展示测试的详细信息

MacBook-Pro:test_demo fujinjie$ pytest -v test_demo8.py
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 1 item                                                                                                                                                                                       

test_demo8.py::test_passing PASSED                                                                                                                                                               [100%]

========================================================================================== 1 passed in 0.01s ===========================================================================================

测试失败

# test_demo8.py

def test_fail():
    assert 1 ==2 

同样在命令行执行pytest test_demo8.py命令

MacBook-Pro:test_demo fujinjie$ pytest test_demo8.py
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 1 item                                                                                                                                                                                       

test_demo8.py F                                                                                                                                                                                  [100%]

=============================================================================================== FAILURES ===============================================================================================
_____________________________________________________________________________________________ test_failing _____________________________________________________________________________________________

    def test_fail():
>       assert 1 == 2
E       assert 1 == 2

test_demo8.py:8: AssertionError
========================================================================================== 1 failed in 0.05s ===========================================================================================

测试结果为失败,pytest使用 F 来标识测试失败FAILED

pytest中使用assert来进行断言。

 

三、标记函数

pytest默认查找当前目录下所有以test开始或者结尾的Python文件,并执行其中所有以test开始或结束的函数(方法)

 

run.py

#--coding:utf-8 --
#run.py
import pytest if __name__ == '__main__': pytest.main(['-v'])

test_demo9.py

#--coding:utf-8 --
#test_demo9.py

def test_demo9_func1():
    assert 1 == 1

def test_demo9_func2():
    assert 2 == 2

test_demo10.py

#--coding:utf-8 --
#test_demo10.py

def test_demo10_func3():
    assert 3 == 3

def test_demo10_func4():
    assert 4 == 4

因为run.py/test_demo9.py/test_demo10.py在同一个demo目录下,所以执行run.py时pytest会查找该目录下所有以test开头或结尾的Python文件,并执行文件中所有以test开头或结尾的函数和方法

============================= test session starts ==============================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo/templates/demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collecting ... collected 4 items

test_demo10.py::test_demo10_func3 PASSED                                 [ 25%]
test_demo10.py::test_demo10_func4 PASSED                                 [ 50%]
test_demo9.py::test_demo9_func1 PASSED                                   [ 75%]
test_demo9.py::test_demo9_func2 PASSED                                   [100%]

============================== 4 passed in 0.02s ===============================

由于某些原因,我只想执行test_demo9_func2()测试用例看是否通过,通过pytest有以下几种方法:

方法一,执行时指定函数名,通过 :: 标记

#--coding:utf-8 --
#run.py
import pytest


if __name__ == '__main__':
    pytest.main(['test_demo9.py::test_demo9_func2','-v'])

或者在命令行中输入

$pytest -v demo/test_demo9.py::test_demo9_func2

运行结果

MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo9.py::test_demo9_func2
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 1 item                                                                                                                                                                                       

demo/test_demo9.py::test_demo9_func2 PASSED                                                                                                                                                      [100%]

========================================================================================== 1 passed in 0.01s ===================================================

 

方法二,使用 -k 选项标识来模糊匹配

匹配执行demo目录下名称中含有func2的测试用例

$ pytest -v -k func2 demo/

执行结果

MacBook-Pro:test_demo fujinjie$ pytest -v -k func2 demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 4 items / 3 deselected / 1 selected                                                                                                                                                          

demo/test_demo9.py::test_demo9_func2 PASSED                                                                                                                                                      [100%]

=================================================================================== 1 passed, 3 deselected in 0.01s =========================================

以上两种方法,第一种只能指定一个测试用例,无法批量执行;第二种需要所有测试名称包含相同的部分名称是才能批量执行。

方法三,直接使用 pytest.mark 在函数(测试用例)上进行标记

#--coding:utf-8 --
#test_demo9.py
import pytest

@pytest.mark.run
def test_demo9_func1():
    assert 1 == 1

@pytest.mark.unrun
def test_demo9_func2():
    assert 2 == 2
#--coding:utf-8 --
#test_demo10.py
import pytest

@pytest.mark.unrun
def test_demo10_func3():
    assert 3 == 3

@pytest.mark.unrun
def test_demo10_func4():
    assert 4 == 4

在命令行输入 pytest -v -m run demo/ 命令执行

MacBook-Pro:test_demo fujinjie$ pytest -v -m run demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 4 items / 3 deselected / 1 selected                                                                                                                                                          

demo/test_demo9.py::test_demo9_func1 PASSED                                                                                                                                                      [100%]

=========================================================================================== warnings summary ==========================

上述4个测试函数,只有被标记为run的 test_demo9_func1( ) 被执行

注:一个函数可以被添加多个标记,多个函数可以添加相同的标记来实现批量执行

运行时 -m 后面可加逻辑

#--coding:utf-8 --
#test_demo9.py
import pytest

@pytest.mark.run
def test_demo9_func1():
    assert 1 == 1

@pytest.mark.commit
@pytest.mark.unrun
def test_demo9_func2():
    assert 2 == 2

执行 pytest -v -m "unrun and commit" demo/

MacBook-Pro:test_demo fujinjie$ pytest -v -m "unrun and commit" demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 4 items / 3 deselected / 1 selected                                                                                                                                                          

demo/test_demo9.py::test_demo9_func2 PASSED                                                                                                                                                      [100%]

被标记为 unrun 和 commit 的测试函数才执行

 

四、跳过测试

在测试工作中面对大批量的测试用例,想对其中某一条跳过不执行,Pytest中使用 pytest.mark.skip 可直接跳过该测试用例

#--coding:utf-8 --
#test_demo10.py
import pytest

@pytest.mark.skip
def test_demo10_func3():
    assert 3 == 3


def test_demo10_func4():
    assert 4 == 4

在命令行执行 pytest -v demo/test_demo10.py

MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo10.py
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 2 items                                                                                                                                                                                      

demo/test_demo10.py::test_demo10_func3 SKIPPED                                                                                                                                                   [ 50%]
demo/test_demo10.py::test_demo10_func4 PASSED                                                                                                                                                    [100%]

===================================================================================== 1 passed, 1 skipped in 0.01s =============================================

执行结果中只有 test_demo10_func4 被执行,test_demo10_func3 直接跳过没执行

五、参数化

当对一个函数进行测试时,通常会给这个函数传递多组参数,模拟各种不同情况,在pytest中就是参数化测试,即每组参数都独立执行一次测试,使用 pytest.mark.parametrize(argnames, argvalues)

#--coding:utf-8 --
#test_demo11.py

import pytest

@pytest.mark.parametrize('password',['12345','123456a','abcdefgh'])
def test_demo_func5(password):
    assert len(password) >= 6

在命令行执行 pytest -v demo/test_demo11.py

MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo11.py
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 3 items                                                                                                                                                                                      

demo/test_demo11.py::test_demo_func5[12345] FAILED                                                                                                                                               [ 33%]
demo/test_demo11.py::test_demo_func5[123456a] PASSED                                                                                                                                             [ 66%]
demo/test_demo11.py::test_demo_func5[abcdefgh] PASSED                                                                                                                                            [100%]

=============================================================================================== FAILURES ===============================================================================================
________________________________________________________________________________________ test_demo_func5[12345] ________________________________________________________________________________________

password = '12345'

    @pytest.mark.parametrize('password',['12345','123456a','abcdefgh'])
    def test_demo_func5(password):
>       assert len(password) >= 6
E       AssertionError: assert 5 >= 6
E        +  where 5 = len('12345')

demo/test_demo11.py:8: AssertionError

通过上述结果可以看出该测试函数被执行了3次,每次都以不同的password参数传入,FAILLED一次,PASSED两次。

传入多个参数

#--coding:utf-8 --
#test_demo11.py

import pytest

@pytest.mark.parametrize('user,password',[('Jack','123456'),('Pluo','123456a'),('Flak','abcdefg')])
def test_demo11_func6(user,password):
    db = {'Jack':'123456',
          'Pluo':'123456a',
          'Flak':'abcdefg'}
    assert db[user] == password

在命令行执行 pytest -v demo/test_demo11.py::test_demo11_func6

MacBook-Pro:test_demo fujinjie$ pytest -v demo/test_demo11.py::test_demo11_func6
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 3 items                                                                                                                                                                                      

demo/test_demo11.py::test_demo11_func6[Jack-123456] PASSED                                                                                                                                       [ 33%]
demo/test_demo11.py::test_demo11_func6[Pluo-123456a] PASSED                                                                                                                                      [ 66%]
demo/test_demo11.py::test_demo11_func6[Flak-abcdefg] PASSED                                                                                                                                      [100%]

========================================================================================== 3 passed in 0.02s ===========================================================================================

 

六、固件Fixture

Fixture是一些函数,pytest会在执行测试函数(用例)之前或之后加载执行它们,比如执行测试函数前数据库的连接和执行完毕后数据库的关闭操作。

Pytest通过 @pytest.fixture() 来定义固件,在pytest中使用conftest.py集中管理固件,更大程度上复用(conftest.py的作用域为其所在的目录和子目录)

 

 

 

conftest.py在demo目录下,因此它的作用域为demo目录下的所有文件以及子文件

conftest.py

#--coding:utf-8 --
#conftest.py

import pytest

@pytest.fixture()
def fixture_func1():
    return '3721'

test_demo11.py

#--coding:utf-8 --
#test_demo11.py

import pytest

def test_demo11_func7(fixture_func1):
    num = '3721'
    assert num == fixture_func1

在 test_demo11.py 中测试函数 test_demo11_func7 直接调用 conftest.py 中的 fixture_func1 固件完成测试

注意:不要显示调用 conftest.py (pytest会根据conftest.py的作用域自动调用),可以把 conftest.py 当作插件来理解。

在命令行执行 pytest -v -k func7 demo/test_demo11.py

MacBook-Pro:test_demo fujinjie$ pytest -v -k func7 demo/test_demo11.py
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /usr/local/bin/python3.7
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '5.3.5', 'py': '1.8.1', 'pluggy': '0.13.1'}, 'Plugins': {'html': '2.0.1', 'allure-pytest': '2.8.10', 'metadata': '1.8.0'}}
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 7 items / 6 deselected / 1 selected                                                                                                                                                          

demo/test_demo11.py::test_demo11_func7 PASSED                                                                                                                                                    [100%]

=================================================================================== 1 passed, 6 deselected in 0.02s ====================================================================================

 七、预处理和后处理

在测试过程中,我们需要在测试开始之前做准备工作,以及在测试结束后做收尾工作,在pytest中通过固件来自动化所有预处理和后处理,使用 yield 关键字将固件分为两部分,yield 之前的代码属于预处理,在测试之前执行,yield 之后的代码属于后处理,将在测试完成后执行。

在 conftest.py 中加入 fixture_func2 固件

#--coding:utf-8 --
#conftest.py

import pytest

@pytest.fixture()
def fixture_func1():
    return '3721'

@pytest.fixture()
def fixture_func2():
    print('测试开始之前')
    yield
    print('测试结束之后')

在 test_demo11.py 的测试函数 test_demo11_func7 中调用固件 fixture_func1 和 fixture_func2

def test_demo11_func7(fixture_func1,fixture_func2):
    num = '3721'
    assert num == fixture_func1

在命令行中执行 pytest --setup-show -s -k func7 demo/

MacBook-Pro:test_demo fujinjie$ pytest --setup-show -s -k func7 demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 11 items / 10 deselected / 1 selected                                                                                                                                                        

demo/test_demo11.py 
        SETUP    F fixture_func1测试开始之前

        SETUP    F fixture_func2
        demo/test_demo11.py::test_demo11_func7 (fixtures used: fixture_func1, fixture_func2).测试结束之后

        TEARDOWN F fixture_func2
        TEARDOWN F fixture_func1

=================================================================================== 1 passed, 10 deselected in 0.02s ===================================================================================

 

八、作用域

pytest使用作用域来进行指定固件的使用范围

定义固件时通过 scope 参数声明作用域,可选项有:

1、function: 函数级,每个测试函数都会执行一次固件;

2、class:类级别,每个测试类执行一次,所有方法都可以使用;

3、module:模块级,每个模块执行一次,模块内函数和方法都可以使用;

4、session:会话级,一次测试只执行一次,所有被找到的函数和方法都可用。

注:固件默认的作用域为 function

conftest.py

@pytest.fixture(scope='function')
def fixture_function():
    pass

@pytest.fixture(scope='module')
def fixture_module():
    pass

@pytest.fixture(scope='session')
def fixture_session():
    pass

@pytest.fixture(scope='class')
def fixture_class():
    pass

test_demo11.py

 def test_demo11_func8(fixture_function,fixture_session,fixture_module):
    pass

在命令行执行 pytest --setup-show -k func8 demo/ 可以看到各固件的作用域与执行顺序

MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k func8 demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 12 items / 11 deselected / 1 selected                                                                                                                                                        

demo/test_demo11.py 
SETUP    S fixture_session
    SETUP    M fixture_module
        SETUP    F fixture_function
        demo/test_demo11.py::test_demo11_func8 (fixtures used: fixture_function, fixture_module, fixture_session).
        TEARDOWN F fixture_function
    TEARDOWN M fixture_module
TEARDOWN S fixture_session

=================================================================================== 1 passed, 11 deselected in 0.02s ============================================================

 

 对于类使用作用域,需要使用 @pytest.mark.usefixtures

test_demo11.py

@pytest.mark.usefixtures('fixture_class')
class TestDemo11Class1:
    def test_demo11_func9(self):
        pass

    def test_demo11_func10(self):
        pass

在命令行执行 pytest --setup-show -k TestDemo11Class1 demo/ 结果如下

MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k TestDemo11Class1 demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 14 items / 12 deselected / 2 selected                                                                                                                                                        

demo/test_demo11.py 
      SETUP    C fixture_class
        demo/test_demo11.py::TestDemo11Class1::test_demo11_func9 (fixtures used: fixture_class).
        demo/test_demo11.py::TestDemo11Class1::test_demo11_func10 (fixtures used: fixture_class).
      TEARDOWN C fixture_class

=================================================================================== 2 passed, 12 deselected in 0.04s ===================================================================================

上述结果可见,该类下的所有测试函数都在这个类级别固件作用范围内

九、自动执行

上述固件,都是通过我们手动指定后才执行的,在pytest中可以在定义固件时指定 autouse 参数让固件自动执行

conftest.py

@pytest.fixture(scope='function',autouse=True)
def fixture_function():
    pass

@pytest.fixture(scope='module',autouse=True)
def fixture_module():
    pass

@pytest.fixture(scope='session',autouse=True)
def fixture_session():
    pass

test_demo11.py

def test_demo11_func11():
    pass

命令行执行 pytest --setup-show -k func11 demo/

MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k func11 demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 15 items / 14 deselected / 1 selected                                                                                                                                                        

demo/test_demo11.py 
SETUP    S fixture_session
    SETUP    M fixture_module
        SETUP    F fixture_function
        demo/test_demo11.py::test_demo11_func11 (fixtures used: fixture_function, fixture_module, fixture_session).
        TEARDOWN F fixture_function
    TEARDOWN M fixture_module
TEARDOWN S fixture_session

=================================================================================== 1 passed, 14 deselected in 0.02s ===================================================================================

结果可见,所有参数 autouse = True 的 fixture 都自动执行了

十、对固件重命名

fixture默认的名称为定义是的函数名称,可以通过 name 选项指定名称

 conftest.py

@pytest.fixture(name='year')
def fixture_year():
    return 2020

test_demo11.py

def test_demo11_func12(year):
    now_year = 2020
    assert now_year == year

执行结果可见,固件名称被命名为 year,可供测试函数直接调用

MacBook-Pro:test_demo fujinjie$ pytest --setup-show -k func12 demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 16 items / 15 deselected / 1 selected                                                                                                                                                        

demo/test_demo11.py 
        SETUP    F year
        demo/test_demo11.py::test_demo11_func12 (fixtures used: year).
        TEARDOWN F year

=================================================================================== 1 passed, 15 deselected in 0.02s ===================================================================================

十一、固件参数化

通过固件调用不同的参数,使测试函数应用与不同的测试场景,提高测试函数的复用性

固件参数化需要使用 pytest 内置的固件 request,并通过 request.param 获取参数

# conftest.py

@pytest.fixture(params=[('参数k1','参数v1'),('参数k2','参数v2'),('参数k3','参数v3')])
def param(request):
    return request.param

@pytest.fixture(autouse=True)
def fixture_param(param):
    print('正在传入参数%s:%s'% param)
    yield
    print('参数%s:%s处理完毕'% param)

在test_demo11.py中加入test_demo11_func13 测试函数

def test_demo11_func13():
    pass

执行结果

MacBook-Pro:test_demo fujinjie$ pytest --setup-show -s -k func13 demo/
========================================================================================= test session starts ==========================================================================================
platform darwin -- Python 3.7.2, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/fujinjie/PycharmProjects/test_demo
plugins: html-2.0.1, allure-pytest-2.8.10, metadata-1.8.0
collected 51 items / 48 deselected / 3 selected                                                                                                                                                        

demo/test_demo11.py 
        SETUP    F param[('参数k1', '参数v1')]正在传入参数参数k1:参数v1

        SETUP    F fixture_param (fixtures used: param)
        demo/test_demo11.py::test_demo11_func13[param0] (fixtures used: fixture_param, param, request).参数参数k1:参数v1处理完毕

        TEARDOWN F fixture_param
        TEARDOWN F param[('参数k1', '参数v1')]
        SETUP    F param[('参数k2', '参数v2')]正在传入参数参数k2:参数v2

        SETUP    F fixture_param (fixtures used: param)
        demo/test_demo11.py::test_demo11_func13[param1] (fixtures used: fixture_param, param, request).参数参数k2:参数v2处理完毕

        TEARDOWN F fixture_param
        TEARDOWN F param[('参数k2', '参数v2')]
        SETUP    F param[('参数k3', '参数v3')]正在传入参数参数k3:参数v3

        SETUP    F fixture_param (fixtures used: param)
        demo/test_demo11.py::test_demo11_func13[param2] (fixtures used: fixture_param, param, request).参数参数k3:参数v3处理完毕

        TEARDOWN F fixture_param
        TEARDOWN F param[('参数k3', '参数v3')]

=================================================================================== 3 passed, 48 deselected in 0.04s ============================================

注意:与函数参数化 @pyest.mark.parametrize 不同,固件是在定义时使用 params 进行参数化,固件参数化依赖内置的 request 以及属性 param

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM