The best in the whole network, Python interface automated testing practical information-project interface case, reading this article is enough…

Table of Contents: Introduction

    • Preface
    • 1. Python programming from entry to proficiency
    • 2. Practical implementation of interface automation projects
    • 3. Web automation project actual combat
    • 4. Practical implementation of App automation project
    • 5. Resumes of first-tier manufacturers
    • 6. Test and develop DevOps system
    • 7. Commonly used automated testing tools
    • 8. JMeter performance test
    • 9. Summary (little surprise at the end)

Foreword

1. What does unit testing mainly do?

Test discovery: Find our test cases from multiple files;
Test execution: execute according to a certain order and rules, and generate results;
Test judgment: judge the difference between expected results and actual results through assertions;
Test report: Statistics of test progress, time consumption, pass rate, and generate test report;

The unit testing framework is just one component of the automated testing framework.

The automated testing framework also includes: design patterns, data-driven, keyword-driven, global configuration file encapsulation, log monitoring, selenium and requests secondary encapsulation, assertions, report emails…

2. Basic usage of the decorator @pytest.mark.parametrize() in pytest

All testing frameworks are inseparable from data-driven, so what is data-driven?

Data-driven: In fact, it means putting the data of our test cases into excel, yaml, csv, and mysql. Then change the data to change the execution results of the test case.

@pytest.mark.parametrize(args_name,args_value)

args_name: the name of the parameter
args_value: The value of the parameter (supported formats: list, tuple, dictionary list, field tuple, namely: [], (), [{},{},{}], ({},{},{}) ), the important thing to note is that this method will be executed as many times as there are parameter values.

pytest default test case rules: (can be modified according to the pytest.ini configuration file)

The module name must start with test_ or _test;
The class name must start with Test;
The method name must start with test;

How to use:

Method 1: The most basic usage

import pytest

class TestApi:

    @pytest.mark.parametrize('args', ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu'])
    def test_01_api(self, args):
        print(args)

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

After executing the above code, the test_01_api use case will be executed four times, and ‘Zhang San’, ‘Li Si’, ‘Wang Wu’, and ‘Zhao Liu’ will be printed out respectively. The -vs command parameter means printing more detailed log information. test_api.py represents the executed file.

Results of the:

Method 2: Usage of unpacking

If we change the format of the incoming parameters, as shown in the figure below, and write the parameter values as two lists, the test case will be executed twice, and two lists will be passed in each time.

Now we pass in two parameter names, as shown in the figure below. If you observe the running results, you will find that the first element in each list will be passed to name, and the second element will be passed to age. This is the usage of unpacking. This method is similar to the data-driven decorator ddt implemented in the unittest framework.

import pytest

class TestApi:

    @pytest.mark.parametrize('name,age', [['Zhang San', 20], ['Wang Wu', 21]])
    def test_01_api(self, name, age):
        print(name, age)
        
if __name__ == '__main__':
    pytest.main(['-vs', 'test_api.py'])

3. Pytest combined with yaml to achieve data drive

1) Introduction to yaml

yaml is a data format saved in a data file, supporting comments, line breaks, and bare strings (the smallest unit of data)

2) yaml purpose

Used for global configuration files: environment, database information, account information, log format, report name.
It is used for more complex multi-interface series connection in interface automation.
Used to write interface test cases.

3) yaml syntax rules

case sensitive
Like Python, hierarchical relationships are expressed through indentation.
It has nothing to do with how many layers are indented, it only has to do with whether the left side is aligned
# represents comments

4) Examples of yaml data composition

map object: key (space) value

Array (list): starts with a set of dashes

Website used to verify whether the yaml file format or json file format is correct: https://www.bejson.com/

Data-driven practice:

Create a new yaml file data.yaml and write the code as follows:

-
  api_name: Get NetEase news
  api_request:
    url: https://api.apiopen.top/getWangYiNews
    method: post
    headers:
      Content-Type: application/json
    params:
      page: 1
      count: 5
  api_validate:
    - eq: {<!-- -->code: 200}

Create a new Python file yaml_util.py to encapsulate the function of reading yaml file data.

import yaml

# Function to read the contents of yaml file
def read_yaml():

    with open('data.yaml', encoding='utf_8', mode='r') as f:
        data = yaml.load(f, Loader=yaml.FullLoader)
        return data

Create a new Python file test_api.py to write test cases

import pytest
import requests
from pytest_yaml.yaml_util import read_yam

class TestApi:

    @pytest.mark.parametrize('args', read_yaml())
    def test_01_api(self, args):
        url = args['api_request']['url']
        method = args['api_request']['method']
        headers = args['api_request']['headers']
        params = args['api_request']['params']

        if method == 'get':
            requests.get(url)
        else:
            resp = requests.post(url, json=params, headers= headers)
            print(resp.json())

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

operation result:

Add assertion

As shown in the figure above, obtain the asserted data list in the yaml file, all multiple assertions, use a for loop to traverse, use the assert method to assert, and succeed after running.

The interface test implemented above is the most basic. It uses an interface, executes a test case, and only asserts once. If used in actual work, this is far from enough.

4. Interface practice

1) Obtain token authentication code interface

Use the WeChat open document to obtain the Access token interface for practice. The interface document is:

According to the interface document, the method is Get, the interface address is: api.weixin.qq.com/cgi-bin/tok…, and the parameters that need to be passed in to the interface are grant_type, appid, and secret.

Use Python to access the interface and print the response value to the console, as shown below:

import unittest
import requests

class TestApi(unittest.TestCase):
    def test_01_get_token(self):
        url = "https://api.weixin.qq.com/cgi-bin/token"
        params = {<!-- -->
            "grant_type": "client_credential",
            "appid": "xxxxxxxxxxxxx",
            "secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
        resp = requests.get(url, params=params)
        print(resp.json())

Add assertion:

Assert whether the returned status code is 200

self.assertEqual(resp.status_code, 200)

Assert whether the returned result contains access_token

self.assertIn('access_token', resp.text)

Assert whether the value of expires_in in the returned result is equal to 7200

self.assertEqual(dict_result['expires_in'], 7200)

Deserialization
Convert json format string to dictionary format dict_result = json.loads(resp.text)
Directly obtain the response content into dictionary format dict_result = resp.json()

import json
import unittest
import requests


class TestApi(unittest.TestCase):
    def test_01_get_token(self):
        url = "https://api.weixin.qq.com/cgi-bin/token"
        params = {<!-- -->
            "grant_type": "client_credential",
            "appid": "xxxxxxxxxxxxx",
            "secret": "xxxxxxxxxxxxxxxxxxx"
        }
        resp = requests.get(url, params=params)
        print(resp.text, type(resp.text))

        #Method 1: Deserialization, convert the string in json format into dictionary format
        dict_result = json.loads(resp.text)
        
        #Method 2: Directly obtain the response content in dictionary format
        #dict_result = resp.json()

        # assertion
        # Assert whether the returned status code is 200
        self.assertEqual(resp.status_code, 200) # Status assertion
        # Assert whether the returned result contains access_token
        self.assertIn('access_token', resp.text) # Business assertion 1
        # Assert whether the value of expires_in in the returned result is equal to 7200
        self.assertEqual(dict_result['expires_in'], 7200) # Business assertion 2

2) Get the tags created by the official account

The interface documentation is as follows:

import unittest
import requests


class TestApi(unittest.TestCase):
    # Define a global variable and class variable
    access_token = ""

    # Get access_token
    def test_01_get_token(self):
        url = "https://api.weixin.qq.com/cgi-bin/token"
        params = {<!-- -->
            "grant_type": "client_credential",
            "appid": "wx5046a51617ff683a",
            "secret": "334c600a9fbbcadac918d5665d7b1d12"
        }
        resp = requests.get(url, params=params)
        print(resp.text, type(resp.text))

        #Deserialize, convert json format string into dictionary format
        dict_result = resp.json()
        # Get the authentication code access_token and save it
        TestApi.access_token = dict_result['access_token']
        # assertion
        # Assert whether the returned status code is 200
        self.assertEqual(resp.status_code, 200) # Status assertion
        # Assert whether the returned result contains access_token
        self.assertIn('access_token', resp.text) # Business assertion 1
        # Assert whether the value of expires_in in the returned result is equal to 7200
        self.assertEqual(dict_result['expires_in'], 7200) # Business assertion 2

    # Get the tags created by the official account
    def test_02_select_flag(self):
        url = "https://api.weixin.qq.com/cgi-bin/tags/get"
        params = {<!-- -->
            "access_token": TestApi.access_token
        }
        resp = requests.get(url, params=params)
        print(resp.json())

        # Assert whether the returned status code is 200
        self.assertEqual(resp.status_code, 200) # Status assertion
        # Assert whether the returned result contains tags
        self.assertIn('tags', resp.text) #Business assertion

3) Interface association

It can be seen from the above interface document that the execution of interface 2 requires the access_token returned in interface 1. So, how to realize the association of access_token?

Define a global variable access_token = “”;

Get the value of access_token in the response content of interface 1 and save it to the global variable TestApi.access_token = dict_result[access_token’]

Pass the global variable access_token as a parameter to “access_token” in interface 2: TestApi.access_token

Global variables can be obtained and saved in the yaml file.

5. Cookie, session, and token authentication solutions

What are cookies?
A cookie is a small piece of text information generated by the server and stored on the client. The format is a dictionary, key-value pairs.

Categories of cookies:
Session level: Save memory and disappear when the browser is closed.
Persistence: Save the hard disk and will only be cleared when the expiration time expires.

How to view cookies?

How cookies implement authentication (principle)

When a client visits the server for the first time, the server will generate a cookie, and then transmit it to the client in the set-cookie through the response header. The client will automatically bring these cookies from the 2nd to N requests.

Fatal weakness: Cookies are stored on the client side, and sensitive information such as usernames, passwords, and ID numbers are not safe.

Use python to implement a login interface and extract the token from the response.

The interface is post request, and the parameters and response results are as follows:

Use python to send a request, the code is as follows:

import requests
import unittest
import json

class TestApi(unittest.TestCase):

    def test_01_api(self):

        url = "http://api-store**************staff/login"

        jsontext = {<!-- -->
            "account": "188********",
            "password": "123456"
        }
        data = {<!-- -->
            "device_type": 30,
            "system": 2,
            "jsonText": json.dumps(jsontext)
        }

        headers = {<!-- -->
            "Content-Type": "application/x-www-form-urlencoded"
        }

        resp = requests.post(url, data=data, json=json,headers=headers)
        print(resp.text)


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

The execution results are as follows:

Get the value of token through regular expression

# Extract the value of token through regular expression
value = re.search('"token":"(. + ?)"', resp.text)
print(value.group(1))

Save the obtained token to a global variable

import re
import requests
import unittest
import json


class TestApi(unittest.TestCase):

    #Define a global variable
    token = ""

    def test_01_api(self):

        url = "http://api***********/login"

        jsontext = {<!-- -->
            "account": "188******",
            "password": "123456"
        }
        data = {<!-- -->
            "device_type": 30,
            "system": 2,
            "jsonText": json.dumps(jsontext)
        }

        headers = {<!-- -->
            "Content-Type": "application/x-www-form-urlencoded"
        }

        resp = requests.post(url, data=data, json=json,headers=headers)
        print(resp.text)

        # Extract the value of token through regular expression
        value = re.search('"token":"(. + ?)"', resp.text)

        # Save the extracted token value as a global variable
        TestApi.token = value.group(1)

        # Subsequent operations that require token can directly use global variables.
        print(TestApi.token)


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

If we need to pass in cookies when testing the next interface, then we can define a global variable test_cookies = “” to save cookies.

Extract cookies through test_cookies = resp.cookies and save them to the global variable test_cookies. Pass in the cookies in the following interface test, namely: requests.post(url, data=data, json=json,
headers=headers, cookies=test_cookies), thus realizing Cookie authentication.

session authentication:

When the user accesses the server for the first time, a sessionid will be saved on the server. This sessionid is encrypted, and then the sessionid will be saved to the client through a cookie. Only the sessionid will be sent when requesting the server.

class TestApi(unittest.TestCase):

    #Define a global variable
    session = ""

    def test_01_api(self):

        url = "http://************"
        TestApi.session = requests.Session()
        #Send sessionid when requesting
        res = TestApi.session.get(url=url)
        print(TestApi.session)
        print(res.json())

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

The fatal weakness of session authentication:

The sessionid is very easy to use for the browser. It only needs to store a string in the cookie. However, the server must store the sessionid of all online users. The more people online at the same time, the greater the overhead, which seriously affects the server’s performance. performance. When the number of users is particularly large, it will cause the server to crash.

Token authentication:

The above solutions all revolve around session, so can we solve it without using sessionid?

If sessionid is not applicable, how to ensure that the data is generated by the server? How to verify it? Where does the user information exist?

So someone thought of generating an encrypted string according to certain rules. The server only verifies it but does not store it. As long as the verification is passed, it means that it was generated by itself. The user information is stored in the encrypted string. In this way, performance and CORS (cross-domain resource sharing) can be solved. , and this encrypted string is the token.

When a user logs in, a token is sent to him. The user only needs to bring this token the next time he requests again.

Token encryption method:
Symmetric encryption: DES AES
Dual-key encryption: RSA
Only encrypt but not decrypt: MD5 SHA

Classification of tokens:
access_token: There is a time limit, limited to 15 minutes
refresh_token: usually 15 days

Similarities and differences between cookies, sessions, and tokens:

Same point:
They are all used for authentication and are generated by the server.

the difference:
Cookies are stored on the client, and sessions are stored on the server. Sessions are more secure than cookies. Therefore, under normal circumstances, important information is placed in the session and unimportant information is placed in the cookie.

The session is stored in the server memory, and the token is stored in the server’s file or database. The advantage of the token is that it saves server resources than the session. The token only needs to be decrypted on the server.

In the process of continuous technological advancement, the above gradually cannot meet the needs of users, and new problems have arisen: third-party payments, banks, and financial projects have higher security requirements, so the interface signature appeared.

The following is the most comprehensive software testing engineer learning knowledge architecture system diagram I compiled in 2023

1. Getting started with Python programming to becoming proficient

Please add a picture description

2. Practical implementation of interface automation project

Please add an image description

3. Web automation project practice

Please add an image description

4. App automation project practice

Please add an image description

5. Resumes of first-tier manufacturers

Please add image description

6. Test and develop DevOps system

Please add a picture description

7. Commonly used automated testing tools

Please add a picture description

8. JMeter performance test

Please add an image description

9. Summary (little surprise at the end)

Through ups and downs, only perseverance can lead to success. Overcome obstacles and move forward bravely, the light of your dreams will eventually illuminate the way forward. Believe in yourself and you will create miracles.

As long as you have courage and perseverance, you will be able to overcome difficulties and realize your dreams. Every step of effort is a ladder to success. Believe in yourself and move forward courageously.

All the way through wind and rain, all the way to sunshine, persevere and move forward bravely, you will eventually reap glory. Every effort is the seed of future success. It will bear fruit with persistence. Believe in yourself and you can create miracles.