Gao fushuai in unit testing, Pytest framework, hand-in-hand teaching, high-order usage practice

Posted by jordanwb on Fri, 03 Dec 2021 17:33:48 +0100

1, Front back approach in xunit style

1. Pre post method of function use case

Use cases are defined in the form of functions in the module, which can be defined through setup_function and teardown_function to define the pre and post methods of function use cases. The use cases are as follows:

def setup_function(function):
    print("Function use case pre method execution")

  
def teardown_function(function):
    print("Function use case post method execution")


def test_01():
    print('----Use case method 01------')

Operation results:

C:\testcases>pytest -s
========================= test session starts =========================
platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0 
cachedir: .pytest_cache
rootdir: C:\testcases
plugins:  testreport-1.1.2
collected 1 item                                                      
test_demo.py
 Function use case pre method execution
----Use case method 01------ .
Function use case post method execution
========================= 1 passed in 0.27s =========================

2. Pre and post methods of test cases in test classes

Class level pre and post methods

Pre and post method setup of test class level in pytest_ Class and teardown_class, which is executed before the execution of the use cases in the test class and after the execution of all the use cases in the test class. The specific usage is as follows:

class TestDome:
    def test_01(self):
        print('----Test case: test_01------')

    def test_02(self):
        print('----Test case: test_02------')

    @classmethod
    def setup_class(cls):
        print("Test class pre method---setup_class---")

    @classmethod
    def teardown_class(cls):
        print("Test class post method---teardown_class---")

Pre and post method at use case level

Pre and post method setup of use case level in test class in pytest_ Method and teardown_method, which is executed before the execution of the use cases in the test class and after the execution of all the use cases in the test class. The specific use is as follows:

class TestDome:

    def test_01(self):
        print('----Test case: test_01------')

    def test_02(self):
        print('----Test case: test_02------')

    @classmethod
    def setup_class(cls):
        print("Test class pre method---setup_class---")

    @classmethod
    def teardown_class(cls):
        print("Test class post method---teardown_class---")

    def setup_method(function):
        print("Pre test case method---setup_method---")

    def teardown_method(function):
        print("Post test case method---teardown_method---")

Operation results

C:\testcases>pytest -s
==================== test session starts ====================
platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0
rootdir: C:\testcases
plugins:  testreport-1.1.2
collected 2 items                                                                                                                                 
test_demo.py 
Test class pre method---setup_class---
Pre test case method---setup_method---
----Test case: test_01------.
Post test case method---teardown_method---
Pre test case method---setup_method---
----Test case: test_02------.
Post test case method---teardown_method---
Test class post method---teardown_class---

==================== 2 passed in 0.30s =======================

3. Pre post method at module level

pytest also has setup_module and teardown_module, two functions used to set module level pre and post methods, are defined in the module and will be executed before and after the execution of all use cases in the whole module. The specific usage is as follows:

class TestDome:

    def test_01(self):
        print('----Test case: test_01------')


class TestDome2:

    def test_02(self):
        print('----Test case: test_02------')
   
  
def setup_module(module):
    print("Pre test method of test module---setup_module---")


def teardown_module(module):
    print("Pre test method of test module---teardown_module---")

Operation results

C:\testcases>pytest -s
====================== test session starts ====================== 
platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0
rootdir: C:\testcases
plugins:testreport-1.1.2
collected 2 items                                                                   
test_demo.py Pre test method of test module---setup_module---
----Test case: test_01------
.----Test case: test_02------
.Pre test method of test module---teardown_module---
====================== 2 passed in 0.27s ====================== 

2, fixture mechanism

Earlier, we introduced the xunit style pre post method in pytest. Next, let's take a look at the use of the more powerful fixture mechanism (test fixture) in pytest.

1. Level and definition of test fixture

The test fixture needs to be defined using the decorator pytest.fixture. The test fixture in pytest has the following levels: use case level, test class level, module level, package level and session level. Next, let's look at the fixture definition syntax.

Fixture definition can specify the level of fixture through the parameter scope. If the fixture level is not specified, the default value of scope is function (use case level)

Use case level: scope = function

Test class level: scope = class

Module level: scope = module

Package level: scope = package

Session level: scope = session

@pytest.fixture(scope='Specifies the level of the fixture')
def work():
    # Pre execution script
    yield 
    # Post execution script

The test fixture is essentially a generator function. When using next to iterate, the producer function will return data to yeild, pause execution, and wait for the next iteration before continuing execution. The pytest fixture uses the generator mechanism to separate the pre and post codes in the test fixture through yeild.

Note: the fixture can only be used within the scope of defining the fixture. If the fixture is defined in a class, it can only be used by test cases in that class. However, if the fixture is defined in the global scope of the module, it can be used for each test case in the module, even if it is defined in a class.

Now that we know how to define a fixture, let's look at how to use a fixture.

2. Use of fixtures

After the test fixture is defined, the test function specifies the fixture to be executed before executing the use case by declaring them as parameters.

When pytest starts running a test, it looks at the formal parameters defined by the test function, and then searches for test fixtures with the same name as these parameters. Once pytest finds them, it runs the fixtures, receives their returns, if any, and passes them as parameters to the test function.

Note: when we use the fixture, if the pre script of the fixture is executed and there is data to be transferred to the use case, the data to be transferred can be written after the yield. In the use case or method using the fixture, the data returned by yeild can be obtained through the defined formal parameters (the use case is introduced in Chapter 2.3)

2.1. Use fixture in use case
Whether it is a test case defined in the form of a function or a test case defined in the form of a method in a test class, it is the same when used. You can directly define a formal parameter with the same name as the fixture to be used.

import pytest

# Define a use case level fixture
@pytest.fixture
def my_fixture():
    print('------my_fixture---Use case pre execution script--------')
    yield
    print('------my_fixture---Post use case execution script--------')

# Function case specifies the test fixture
def test_func__01(my_fixture):
    print("test case----test_func__01----")


class TestDome:
    # Function case specifies the test fixture
    def test_02(self, my_fixture):
        print('----Test case: test_02------')
  
     # Function case specifies the test fixture
    def test_03(self):
        print('----Test case: test_03------')

Operation results

C:\testcases>pytest -s
======================== test session starts ========================
platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0
rootdir: C:\testcases
plugins: testreport-1.1.2
collected 2 items  
test_demo.py 
------my_fixture---Pre execution script--------
test case----test_func__01----.
------my_fixture---Post execution script--------
------my_fixture---Pre execution script--------
----Test case: test_02------.
------my_fixture---Post execution script--------
----Test case: test_03------
======================== 2 passed in 0.27s ========================

Test above_ func__ 01 and test_02 these two use cases specify the test fixture when defining, and test_03, no fixture is specified for execution. When executing the use case, the library sees the use case with the specified fixture and executes the corresponding fixture.

2.2 designated fixtures for test classes and modules

Above, we specify the test fixture for a single test case by adding formal parameters to the use case method. If there are many test cases in a test class or many test cases in a module, the same test fixture should be specified. If necessary, we can specify the test fixture for the test class or test module through use fixtures.

Assign fixtures to all use cases in the test class

# All test cases of the TestDome test class execute my_fixture this fixture
@pytest.mark.usefixtures('my_fixture This fixture')
class TestDome:
    # Function case specifies the test fixture
    def test_02(self):
        print('----Test case: test_01------')

    # Function case specifies the test fixture
    def test_03(self):
        print('----Test case: test_02------')

Use pytestmark to specify the fixture to be executed by all use cases of the module at the test module level

# test_demo.py

# All use cases in the current module execute my_fixture this test fixture
pytestmark = pytest.mark.usefixtures('my_fixture')

# Function case specifies the test fixture
def test_func__01(my_fixture):
    print("Test case———— test_func__01---")

  
class TestDome:
    # Function case specifies the test fixture
    def test_02(self):
        print('----Test case: test_01------')

    # Function case specifies the test fixture
    def test_03(self):
        print('----Test case: test_02------')

2.3. Reference fixture in fixture

One of the biggest advantages of pytest is its extremely flexible fixture system. Through the test fixture, we can split the extremely complex front and rear dependencies into simpler and single function test fixtures, and organize the complex dependency environment required by different use cases by referencing other fixtures in the fixture. Next, we show you how to use it through a case.

import pytest
# User registered fixture
@pytest.fixture
def register_user():
    print('---User registered fixture pre execution----')
    # ... the registration code is omitted, and the registered user information is as follows
    user_info = {'user': 'lemonban', 'pwd': '123456'}
    yield user_info
    print('---User registered fixture post execution----')


# The user logs in to the fixture and uses register by defining formal parameters_ Use this fixture
@pytest.fixture
def user_login(register_user):
    print('---Pre execution of fixture logged in by user----')
    # Get register_ After the user outcome pre script is executed, the data passed by yeild
    user_info = register_user
    # ... the login code is omitted, and the following is the token obtained by login
    token = 'sdjasjdask'
    yield token
    print('---Fixture post execution after user login----')

# Function use cases specify the use of test fixtures_ login
def test_func__01(user_login):
    token = user_login
    print("Test case fixture user_login Passed on token:",token)
    print("test case---test_func__01---")

Operation results

C:\testcases>pytest -s
======================== test session starts ========================
platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0
rootdir: C:\testcases
plugins: testreport-1.1.2
collected 1 item  
test_demo.py 
---User registered fixture pre execution----
fixture register_user User information transmitted: {'user': 'lemonban', 'pwd': '123456'}
---Pre execution of fixture logged in by user----
Test case fixture user_login Passed on token: sdjasjdask
 test case---test_func__01---.
---Fixture post execution after user login----
---User registered fixture post execution----

2.4 automatic fixture

When defining the test fixture, we can add the parameter autouse=True to the decorator of the fixture to make the fixture become an automatically executed fixture. Specific cases are as follows:

import pytest


@pytest.fixture(autouse=True)
def my_fixture():
    print('------my_fixture---Pre execution script--------')
    yield
    print('------my_fixture---Post execution script--------')


class TestDome:
    # Function case specifies the test fixture
    def test_02(self):
        print('----Test case: test_01------')

    # Function case specifies the test fixture
    def test_03(self):
        print('----Test case: test_02------')


class TestDome2:
    # Function case specifies the test fixture
    def test_03(self):
        print('----Test case: test_03------')

Execution results:

C:\testcases>pytest -s
======================== test session starts ========================
platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0
rootdir: C:\testcases
plugins: testreport-1.1.2
collected 3 items    
test_demo.py
------my_fixture---Pre execution script--------
----Test case: test_01------.
------my_fixture---Post execution script--------
------my_fixture---Pre execution script--------
----Test case: test_02------.
------my_fixture---Post execution script--------
------my_fixture---Pre execution script--------
----Test case: test_03------.
------my_fixture---Post execution script--------
======================== 3 passed in 0.29s ========================

From the above execution results, we can see that the test fixture is automatically executed before each use case is executed_ fixture

3,conftest.py

In the test of a project, in most cases, multiple classes, modules, or packages will use the same test fixture. In this case, if we define the test fixture in a module, it cannot be shared. In this case, we can put the test fixture to be shared into a separate conf test.py file, so that multiple test modules can be shared

PS: when pytest runs the test, if there is conf test.py in the project, then pytest will automatically load the contents of the conf test.py module. You can see the plug-in module that pytest will automatically load from conf test. The subsequent tutorials will involve defining the hooks function of pytest in conf test.py

Next, let's take a look at a case where conftest.py defines a test fixture

Define the test fixture in conf test.py_ fixture

# conftest.py

import pytest

@pytest.fixture
def my_fixture():
    print('------my_fixture---Pre execution script--------')
    yield
    print('------my_fixture---Post execution script--------')

In test_ The use case of demo1.py uses the fixture defined in conf test.py

# test_demo1.py
class TestDome:
    # Function case specifies the test fixture
    def test_02(self,my_fixture):
        print('----Test case: test_01------')

    # Function case specifies the test fixture
    def test_03(self,my_fixture):
        print('----Test case: test_02------')

In test_ The use case of demo2.py uses the fixture defined in conf test.py

# test_demo2.py
class TestDome2:
    # Function case specifies the test fixture
    def test_03(self,my_fixture):
        print('----Test case: test_03------')

Execution results:

C:\testcases>pytest -s
======================== test session starts ========================
platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0
rootdir: C:\testcases
plugins: testreport-1.1.2
collected 3 items
test_demo.py 
------my_fixture---Pre execution script--------
----Test case: test_01------.
------my_fixture---Post execution script--------
------my_fixture---Pre execution script--------
----Test case: test_02------.
------my_fixture---Post execution script--------
test_demo2.py 
------my_fixture---Pre execution script--------
----Test case: test_03------.
------my_fixture---Post execution script--------
======================== 3 passed in 0.29s ========================

In the above case, we can find that_ Demo.py and test_ The test cases in demo2.py can successfully use the test cases in confitest.py.

The following is a supporting document, which should be the most comprehensive and complete war preparation warehouse for [software testing] friends. This warehouse has also accompanied me through the most difficult journey. I hope it can also help you!

These can be used in official account: sad spicy bar! Get it for free, and a 216 page interview document for software test engineers. And the corresponding video learning tutorials for free!, The materials include basic knowledge, Linux essentials, Shell, Internet program principles, Mysql database, special topics of packet capture tools, interface test tools, test advanced Python programming, Web automation test, APP automation test, interface automation test, advanced test continuation, test architecture, development test framework, performance test, security test, etc.

Don't fight alone in learning. It's best to stay together and grow together. The effect of mass effect is very powerful. If we study together and punch in together, we will have more motivation to learn and stick to it. You can join our testing technology exchange group: 914172719 (there are various software testing resources and technical discussions)

Friends who like software testing, if my blog is helpful to you and if you like my blog content, please click "like", "comment" and "collect" for three times!

Haowen recommendation

Job transfer interview, job hopping interview, these interview skills that software testers must know!

Interview experience: move bricks in first tier cities! Another software testing post, 5000 will be satisfied

Interviewer: I've worked for three years and have a preliminary test? I'm afraid your title of software test engineer should be enclosed in double quotation marks

What kind of person is suitable for software testing?

The man who left work on time was promoted before me

The test post changed jobs repeatedly and disappeared

Topics: Python Programmer unit testing software testing IT