Explosive liver finishing, Python automated testing - Pytest parameterized actual combat packaging, an article to get through...


foreword

to parameterize?
The popular understanding is that when defining a test class or test function, parameters corresponding to different test cases can be passed in, so as to execute multiple test cases.

For example:
to test the login interface, assuming that there are 3 use cases, login with correct account and password, login with correct account and wrong password, and login with incorrect account and password, then we only need to define a login test function test_login(), and then use these 3 items Use the parameters corresponding to the case to call test_login().

DDT can be used for parameterization in unittest, and a very convenient parameterization method is also provided in pytest, that is, the decorator @pytest.mark.parametrize() is used.

Generally written as pytest.mark.parametrize("argnames", argvalues).
Among them:
argnames is the parameter name, which can be single or multiple, and multiple writing methods are "argname1, argname2, ...";
argvalues ​​is the parameter value, and the type must be list (it can be a tuple for a single parameter, and must be a tuple for multiple parameters list, so it is best to unify);

For example, there are the following interfaces:
Requested login interface information:

接口url:http://127.0.0.1:5000/login
请求方式:post
请求参数:
响应信息:

1. A single parameter

When only one parameter needs to be passed in, the example is as follows:

# 待测试函数
def sum(a):
    return a+1

# 单个参数
data = [1, 2, 3, 4]
@pytest.mark.parametrize("item", data)
def test_add(item):
    actual = sum(item)
    print("\n{}".format(actual))
    # assert actual == 3

if __name__ == '__main__':
    pytest.main()

Note:
The first parameter in @pytest.mark.parametrize() must be in the form of a string to identify the input parameters of the test function. As in the above example, the parameter passed in the defined test function test_login() is named item, then the first parameter of @pytest.mark.parametrize() is "item".

The result of the operation is as follows:

rootdir: E:\blog\python接口自动化\apiAutoTest, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1
collecting ... collected 4 items

test_case_2.py::test_add[1] PASSED                                       [ 25%]
2

test_case_2.py::test_add[2] PASSED                                       [ 50%]
3

test_case_2.py::test_add[3] PASSED                                       [ 75%]
4

test_case_2.py::test_add[4] PASSED                                       [100%]
5

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

As can be seen from the results, the test function passed in the parameters in data respectively, and was executed 5 times in total.

2. Multiple parameters

When the test case needs to pass in multiple parameters, the first parameter of @pytest.mark.parametrize() is also a string, and the multiple parameters of the test case are separated by commas.

Example:

import pytest
import requests
import json

# 列表嵌套元组
data = [("lilei", "123456"), ("hanmeimei", "888888")]
# 列表嵌套列表
# data = [["lilei", "123456"], ["hanmeimei", "888888"]]

@pytest.mark.parametrize("username, password", data)
def test_login(username, password):
    headers = {
    
    "Content-Type": "application/json;charset=utf8"}
    url = "http://127.0.0.1:5000/login"
    _data = {
    
    
        "username": username,
        "password": password
    }
    res = requests.post(url=url, headers=headers, json=_data).text
    res = json.loads(res)
    assert res['code'] == 1000


if __name__ == '__main__':
    pytest.main()

Note:
The format of data in the code can be a list nested list, or a list nested tuple. Each list or tuple in the list represents a set of independent request parameters.
"username, password" cannot be written as "username", "password".

The result of the operation is as follows:

A1

From the results, we can also see the parameters passed in each execution, as shown in the underlined part.

The example here is 2 parameters. When 3 or more parameters are passed in, the writing method is the same. Be sure to pay attention to the one-to-one correspondence between them, as shown in the following figure:

A2

3. Parameterize the test class

The above examples are all parameterized test functions, so how to parameterize test classes?

In fact, the parameterization of the test class is to parameterize the test methods in the test class.

The number of parameters identified in @pytest.mark.parametrize() must be consistent with the parameters of the test method in the class. Examples are as follows:

# 将登陆接口请求单独进行了封装,仅仅只是为了方便下面的示例
def login(username, password):
    headers = {
    
    "Content-Type": "application/json;charset=utf8"}
    url = "http://127.0.0.1:5000/login"
    _data = {
    
    
        "username": username,
        "password": password
    }
    res = requests.post(url=url, headers=headers, json=_data).text
    res = json.loads(res)
    return res

# 测试类参数化
data = [
    ("lilei", "123456"), ("hanmeimei", "888888")
]
@pytest.mark.parametrize("username, password", data)
class TestLogin:
    def test_login_01(self, username, password):
        res = login(username, password)
        assert res['code'] == 1000

    def test_login_02(self, username, password):
        res = login(username, password)
        assert res['msg'] == "登录成功!"

if __name__ == '__main__':
    pytest.main(["-s"])

The result of the operation is as follows:

A3

It can be seen from the results that a total of 4 executions are performed, and each test method in the test class is executed 2 times, that is, each test method executes each set of parameters in the data once.

Note:
Here we still need to emphasize the corresponding relationship of parameters, that is, the first parameter in @pytest.mark.parametrize() needs to correspond one-to-one with the parameters of the test method under the test class.

4. Parameter combination

In the process of writing test cases, sometimes it is necessary to combine parameters for interface requests. For example, in the login interface of the example, the usernames include lilei and hanmeimei, and the passwords include 123456 and 888888. There are four situations for combining them:

{
    
    "username": "lilei", "password": "123456"}
{
    
    "username": "lilei", "password": "888888"}
{
    
    "username": "hanmeimei", "password": "123456"}
{
    
    "username": "hanmeimei", "password": "888888"}

@pytest.mark.parametrize() also provides such a parameter combination function, the writing format example is as follows:

import pytest
import requests
import json


username = ["lilei", "hanmeimei"]
password = ["123456", "888888"]

@pytest.mark.parametrize("password", password)
@pytest.mark.parametrize("username", username)
def test_login(username, password):
    headers = {
    
    "Content-Type": "application/json;charset=utf8"}
    url = "http://127.0.0.1:5000/login"
    _data = {
    
    
        "username": username,
        "password": password
    }
    res = requests.post(url=url, headers=headers, json=_data).text
    res = json.loads(res)
    assert res['code'] == 1000
	
	
if __name__ == '__main__':
    pytest.main()

The result of the operation is as follows:

rootdir: E:\blog\python接口自动化\apiAutoTest, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1
collecting ... collected 4 items

test_case_5.py::test_login[lilei-123456] PASSED                          [ 25%]
test_case_5.py::test_login[lilei-888888] FAILED                          [ 50%]
test_case_5.py::test_login[hanmeimei-123456] FAILED                      [ 75%]
test_case_5.py::test_login[hanmeimei-888888] PASSED                      [100%]
=========================== short test summary info ===========================
FAILED test_case_5.py::test_login[lilei-888888] - assert 1001 == 1000
FAILED test_case_5.py::test_login[hanmeimei-123456] - assert 1001 == 1000
========================= 2 failed, 2 passed in 0.18s =========================

It can be seen from the results that there are 4 combinations of 2 usernames and 2 passwords, and they are executed 4 times in total. If there are 3 usernames and 2 passwords, then there are 6 combinations of parameters, and so on.

Note:
The test cases in the above examples are just examples, and the login interface test script and test data in the actual project will be different.

5. Increase the readability of test results

From the running results of the example, we can see that in order to distinguish the parameterized running results, the execution case names composed of parameters will be displayed in the results, and it is very convenient to see which use cases of parameter combinations are executed.

Example:

A5

But this is just a simple display. If there are many and complicated parameters, it is not clear enough to display it in this way. Some explanations need to be added to make it clear at a glance.

Therefore, there are two ways to customize the display results of the underlined part in the above figure in @pytest.mark.parametrize(), that is, use the parameter ids provided by @pytest.mark.parametrize() to customize, or use pytest.param The parameter id in () is customized.

ids (recommended)
Examples of how to use ids are as follows:

import pytest
import requests
import json


data = [("lilei", "123456"), ("hanmeimei", "888888")]
ids = ["username:{}-password:{}".format(username, password) for username, password in data]
@pytest.mark.parametrize("username, password", data, ids=ids)
def test_login(username, password):
    headers = {
    
    "Content-Type": "application/json;charset=utf8"}
    url = "http://127.0.0.1:5000/login"
    _data = {
    
    
        "username": username,
        "password": password
    }
    res = requests.post(url=url, headers=headers, json=_data).text
    res = json.loads(res)
    assert res['code'] == 1000
    

if __name__ == '__main__':
    pytest.main()

It can be seen from the writing method that ids is a list, and its length is consistent with the number of groups of parameter combinations.

The result of the operation is as follows:

A6

Comparing the above execution results, we can see the difference between the ids custom execution results and the default execution results. During use, it needs to be customized according to the actual situation.

An example of how to use id
is as follows:

import pytest
import requests
import json


data = [
    pytest.param("lilei", "123456", id="correct username and correct password"),
    pytest.param("lilei", "111111", id="correct user name and wrong password")
]

@pytest.mark.parametrize("username, password", data)
def test_login(username, password):
    headers = {
    
    "Content-Type": "application/json;charset=utf8"}
    url = "http://127.0.0.1:5000/login"
    _data = {
    
    
        "username": username,
        "password": password
    }
    res = requests.post(url=url, headers=headers, json=_data).text
    res = json.loads(res)
    assert res['code'] == 1000


if __name__ == '__main__':
    pytest.main()

The result of the operation is as follows:

A7

The following is the most complete software test engineer learning knowledge architecture system diagram in 2023 that I compiled

1. From entry to mastery of Python programming

Please add a picture description

2. Interface automation project actual combat

Please add a picture description

3. Actual Combat of Web Automation Project

Please add a picture description

4. Actual Combat of App Automation Project

Please add a picture description

5. Resume of first-tier manufacturers

Please add a picture description

6. Test and develop DevOps system

Please add a picture description

7. Commonly used automated testing tools

Please add a picture description

Eight, JMeter performance test

Please add a picture description

9. Summary (little surprise at the end)

Struggle is a long journey, and pain and suffering are just trials leading to success. Don't be afraid of difficulties, stick to your beliefs, and water the flowers of your dreams with sweat. Believe in yourself and go forward bravely, you will create your own brilliance and leave a footprint without regrets!

The flame of persistence burns the heart, and the unyielding courage dispels the darkness. Let go of your fear, meet challenges, and keep striving. Every effort forges tenacity, and every struggle opens a new chapter. Go forward bravely and chase your dreams.

On the stage of life, only struggle can compose a brilliant movement. Don't be afraid of difficulties, but face challenges bravely. Keep working hard, never give up, believe in your own strength, you will create an unexpected and wonderful life!

Guess you like

Origin blog.csdn.net/shuang_waiwai/article/details/132230699