Use of pytest framework fixture

Posted by BDKR on Sun, 16 Jan 2022 12:21:04 +0100

catalogue

fixture advantages

Scope of fixture

fixture source code details

scope range of four parameters

scope="function"

 scope="class"

 scope="module"

scope="session"

conftest.py

1. Disposition

2. Scope of action

Three methods of calling fixture

1. The method in the function or class directly passes the name of the function parameter of the fixture

2. Use the decorator @ pytest mark. Usefixtures () decorates the use cases that need to be run

3. Superimpose usefixtures

Difference between using fixtures and passing fixtures

fixture auto use autouse=True

When using the pytest framework to write a case, you must take its command specification to the case, so that the framework can recognize which cases need to be executed and which do not need to be executed.

Use case design principles:

The file name is in test_ * Py files and*_ test.py

With test_ Function at the beginning

Classes starting with Test

With test_ Method at the beginning

fixture advantages

First feature should have the following advantages over setup and teardown

  • The naming method is flexible and not limited to setup and teardown
  • conftest. Data sharing can be realized in py configuration, and some configurations can be found automatically without import
  • scope="module" can implement multiple py cross file sharing front, each py file called once
  • scope="session" to implement multiple py uses one session across files to complete multiple use cases
  • Have independent names and activate them by declaring their use from test functions, modules, classes, or the entire project
  • Implemented in a modular manner, each fixture can call each other
  • Fixtures range from simple unit tests to complex function tests. You can configure parameters for fixture s, or cross function, class, module or the entire test session range

Scope of fixture

There is a scope parameter in the fixture to control the scope of the fixture: session > module > class > function

Function: every function or method will be called

Class: each class is called once, and there can be multiple methods in a class

module: each py file is called once, and there are multiple function s and class es in this file

session: multiple files can be called once, and can be used across multiple files py file call, each The py file is the module

fixture source code details

You can use the decorator (with or without parameters) to define the fixture function. The name of the fixture function can be invoked later. It will be called before running the test: the test module or class can use pytest.. mark. Usefixtures (fixture name) tag. The test function can directly use the fixture name as the input parameter. In this case, the function returned by the fixture instance from the fixture will be injected.

fixture(scope='function',params=None,autouse=False,ids=None,name=None):

scope: there are four level parameters "function" (default), "class", "module" and "session"

params: an optional parameter list that will cause multiple parameters to call the fixture function and all tests to use it.

autouse: if True, activate fixture func for all tests to see it. If False, the display requires a reference to activate the fixture

ids: a list of each string ID, each string corresponding to params, so that they are part of the test ID. If no ID is provided, they are automatically generated from params

Name: the name of the fixture. This defaults to the name of the decorator function. If the first mock exam is used in the unified module of fixture, the function name of the fixture will be obscured by the function of the request fixture. arg will decorate the function command "fixture_<fixturename>" and use "@pytest.fixture (name='<fixturename>')" to solve the problem.

scope the range of the four parameters

scope="function"

@pytest. If fixture () does not write parameters, the parameter is scope="function". Its scope is to run each test case before it comes, and the destroyed code runs after the test case.

Example 1:

#scope="function"

import pytest

@pytest.fixture()
def test1():
    a="Xiao Ming"
    print("\n Outgoing a")
    return a

@pytest.fixture(scope='function')
def test2():
    b="male"
    print("Outgoing b")
    return b

def test3(test1):
    name="Xiao Ming"
    print("find name")
    assert test1==name

def test4(test2):
    sex="male"
    print("find sex")
    assert test2==sex


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

Operation results:

 scope="class"

When the fixture is at the class level, if multiple use cases in a class call the fixture once, the fixture will only be executed once before the start of all use cases in this class.

Example 2:

#scope="class"

import pytest

@pytest.fixture(scope="class")
def test1():
    a="Xiao Ming"
    print("It came out%s,Only in class All use cases in are executed only once"%a)
    return a

class Test:
    def test2(self,test1):
        name="Xiao Ming"
        print("find name")
        assert test1==name

    def test3(self,test1):
        sex="Xiao Ming"
        print("find sex")
        assert test1==sex

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

Operation results:

 scope="module"

When the fixture is module, it is displayed in the current All use cases in the py script are executed only once before starting.

Example 3:

#scope="module"

import pytest

@pytest.fixture(scope="module")
def test1():
    a="Xiao Ming"
    print("\n It came out%s,Only in the current py Execute once in the file"%a)
    return a

def test2(test1):
    name="Xiao Ming"
    print("find name")
    assert test1==name

class Test():
    def test3(self,test1):
        sex="Xiao Ming"
        print("find sex")
        assert test1==sex

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

Operation results:

scope="session"

If the fixture is at the session level, it can span py module calls, that is, when we have multiple py file, if multiple use cases only need to call fixture once, it can be set to scope="session" and written to confitest py file.

Example 4:

conftest. When the PY file name is fixed, pytest will automatically recognize the file. Put it in the root directory of the project and it can be called globally. If it is placed in a package, it will be valid in the changed package.

The file directory is:

conftest.py file:

import pytest

@pytest.fixture(scope="session")
def test1():
    name="Xiao Ming"
    print("Get%s"%name)
    return name

New test_04.py file:

#scope="session"

import pytest

def test2(test1):
    name="Xiao Ming"
    print("find name")
    assert test1==name

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

New test_05.py file:

#scope="session"

import pytest

class Test:
    def test3(self,test1):
        sex="Xiao Ming"
        print("find sex")
        assert test1==sex
        
if __name__ == "__main__":
    pytest.main(["-s", "test_04.py"])

You need to execute two py files at the same time. You can execute the command in the directory where the PY file is located in the cmd environment: pytest -s test_04.py test_05.py 

Operation results:

Example 5:

If I want to implement the following scenarios:
Use case 1 needs to log in first, use case 2 does not need to log in, and use case 3 needs to log in first. Preset conditions of user-defined test cases.

Create a new file test_fixture.py:

#coding:utf-8
#Realize the following scenarios: use case 1 needs to log in first, use case 2 does not need to log in, and use case 3 needs to log in first

import pytest

# Default scope="function" without parameters
@pytest.fixture()
def login():
    print("Enter the account and password to log in first")

def test_1(login):
    print("Case 1: you need to log in first, and then click the personal center")
def test_2(login):
    print("Use case 2: no login required")
def test_3(login):
    print("Use case 3: you need to log in first, and then click my")

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

Operation results:

conftest.py

1. Disposition

1. The above case is in the same py file, multiple use cases call a login function, if there are multiple py files need to call this login function, so you can't write the login into the use case.
At this time, there should be a configuration file to manage some preset operation scenarios separately. Confitest is read by default in pytest Py.

conftest. The following points should be noted for py configuration:

  • conftest.py configuration script name is fixed and cannot be changed
  • conftest.py and the running use case should be in the same pakage and have__ init__.py file
  • Import is not required to import confitest Py and pytest examples will be found automatically

2. Scope of action

Multiple confists can be built under one project Py file, which is generally set in the project root directory. The confitest file plays a global role. You can also put conf test. In different subdirectories Py files, the scope of action can only take effect at the change level and the following directories.

  • The scope of conf test is different at different levels
  • Conf test cannot be called across modules (module calls are not used here)

Three methods of calling fixture

1. The method in the function or class directly passes the name of the function parameter of the fixture

New test_06.py file:

#The method in the function or class directly passes the name of the function parameter of the fixture

import pytest

@pytest.fixture()
def test1():
    print("\n Start execution-------")

def test2(test1):
    print("-----Case 1 execution-----")

class Test:
    def test3(self,test1):
        print("------Case 2 execution-------")

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

Operation results:

2. Use the decorator @ pytest mark. Usefixtures () decorates the use cases that need to be run

New test_07.py file:

#Use the decorator @ pytest mark. Usefixtures () decorates the use cases that need to be run

import pytest

@pytest.fixture()
def test1():
    print("\n Start execution-------")

@pytest.mark.usefixtures("test1")
def test2():
    print("------Use case 1 begins execution-----")
@pytest.mark.usefixtures("test1")
class Test:
    def test3(self):
        print("------Use case 2 begins execution-----")
    def test4(self):
        print("------Use case 3 begins execution------")

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

Operation results:

3. Superimpose usefixtures

If a method or a class use case wants to call multiple fixtures at the same time, you can use @ pytest mark. Usefixture(). Pay attention to the stacking sequence, and put the bottom layer first and then the upper layer.

#Superimpose usefixtures

import pytest

@pytest.fixture()
def test1():
    print("\n Start execution 111-------")
@pytest.fixture()
def test2():
    print("\n Start execution 222-------")

@pytest.mark.usefixtures("test1")
@pytest.mark.usefixtures("test2")
def test3():
    print("------Use case 1 begins execution-----")

@pytest.mark.usefixtures("test1")
@pytest.mark.usefixtures("test2")
class Test:
    def test4(self):
        print("------Use case 2 begins execution-----")
    def test5(self):
        print("------Use case 3 begins execution------")

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

Operation results:

Difference between using fixtures and passing fixtures

If the fixture has a return value, the usefixture cannot obtain the return value. This is the difference between the decorator usefixture and the fixture parameter directly passed by the use case.

When a fixture needs to use the parameters from return, you can only use the parameter name. When the parameters are passed in directly, you don't need to use the parameters from return. Both methods can be used.

fixture auto use autouse=True

When there are many use cases, it is troublesome to pass this parameter every time. There is a parameter autouse in the fixture, which is False by default. If it is not enabled, it can be set to True to enable the automatic use of the fixture function, so that the use case does not have to pass parameters every time

Set autouse to True to call the fixture function automatically

New test_09.py file:

#fixture auto use autouse=True

import pytest

@pytest.fixture(scope='module', autouse=True)
def test1():
    print('\n Start execution module-------')

@pytest.fixture(scope='class', autouse=True)
def test2():
    print('\n Start execution class--------')

@pytest.fixture(scope='function', autouse=True)
def test3():
    print('\n Start execution function--------')

def test1():
    print('------Case 1 execution------')


def test2():
    print('-------Case 2 execution------')


class Test:
    def test3(self):
        print('------Use case 3 execution------')

    def test4(self):
        print('-------Use case 4 execution-------')


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

Operation results:

Topics: Python pytest