Python3 interface automated testing project practice (WEB project)

1.1 Interface test project construction

1.1.1 Deployment of Education Bureau Enrollment Management System

The Education Bureau enrollment management system is based on java+mysql. Its deployment process is introduced below.

1. Download the deployment file from my network disk.

 

2. Install jdk and configure environment variables.

Click

file to install.

 

The next step is to install directly.

My installation path is C:\Program Files\Java\jdk1.7.0_17.

After the installation is complete, environment variables need to be set so that the compiler can be used normally. Right-click "Computer" and select "Properties", select "Advanced System Settings" on the left à select the "Advanced" tab above and click the "Environment Variables" button in the lower right corner.

The dialog box that pops up next will appear with user variables and system variables. User variables are valid for the current login account, and system variables are valid for all users. Readers can set them as needed.

Methods/steps for configuring environment variables:

1). Click New in the system variables, fill in JAVA_HOME for the variable name, and fill in the JDK installation path for the variable value. Here, fill in "C:\Program Files\Java\jdk1.7.0_17".

2). Click on the new variable name in the system variables to fill in the CLASSPATH and the variable value. ".;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar", be careful not to forget the preceding dot and the semicolon in the middle.

3). Find the Path variable in the system variables. It comes with the system and does not need to be created. Double-click Path. Since the original variable value already exists, ";%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin" should be added after the existing variable. Note the preceding semicolon.

Verification method: Enter the cmd command in the run box, press Enter and enter javac, and press Enter to display the following screen.

 

3. Unzip the apache-tomcat-7.0.42  compressed package and put the recruit.students.war  package  under E:\apache-tomcat-7.0.42\webapps.

 

4. Click to install the mysql server.

 

Set mysql account and password: root /root

By default, the installation is completed in the next step.

5. Use the mysql  client tool navicat  to connect to mysql -> create a new recruit_students  library.

 

6. Import the recruit_students_sql  data file into the newly created library.

 

7. After the import is completed, you will see some tables as shown below.

 

8. Modify the database configuration file under the war package: datasource.properties .

E:\apache-tomcat-7.0.42\webapps\recruit.students\WEB-INF\classes 下。

 

Configure the URL of jdbc.

 

9.mysql database user access authorization.

 

Authorization statement:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;

commit;

10. Click startup under  E:\apache-tomcat-7.0.42\bin to start tomcat.

 

11. Access the Education Bureau admissions system.

Access address: http://127.0.0.1:8090/recruit.students/login/view .

Initial account and password: admin /test123

 

Note: The default port of tomcat is 8080. I used 8090 because the port of tomcat was modified.

17.1.2 Function list of the Education Bureau’s enrollment management system

 

1.2 The first interface test case of the project

Implementation steps of use case for Education Bureau Enrollment Management System login interface:

1. Open the packet capture tool: fiddler.

2. Log in to the Education Bureau’s enrollment management system.

3. Capture the login http request.

4. Analyze the login http request (request address, whether to redirect, get request or post request, request header information, request response).

5. Data processing (processing the captured header information)

6. Write interface code.

7. Manually verify the interface test results. (I’ll talk about assertions later)

 

Step 1: Analyze the data captured by fiddler.

[Request method]: get with parameters

[Request address]: http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C

[Request header information]:

Host: 127.0.0.1:8090

Connection: keep-alive

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Refer: http://127.0.0.1:8090/recruit.students/login/view

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9

Cookie: JSESSIONID=AED5BBB1B5E4F9BEDCC3A0FC88668871; userInfoCookie=""

[requested response]: empty

The requested response is empty because when logging in, a jump was made. The status code is: 302, which jumps to

 The address http://127.0.0.1:8090/recruit.students/school/manage/index has a status code of 200.

 

Check the response requested by the address http://127.0.0.1:8090/recruit.students/school/manage/index  . What is returned is the information after login.

 

Through analysis, we clearly understand the situation of this interface.

Step 2: Then you need to process the request header information, remove some useless request header information, and keep it as follows:

"Connection": "keep-alive",

"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

"Referer": "http://127.0.0.1:8090/recruit.students/login/view",

[Connection]: If you only test the login interface, this parameter can be removed. If you need to test the login and create a new school, then this header information needs to be retained.

[User-Agent]: Simulates the real behavior of users using a browser to access a Web website, required for each interface.

[Referer]: Used when logging in for redirection.

Step 3: Finally write the code to implement it.

Program implementation:

Method 1: Write the complete URL directly on the URL.

import requests

url="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless header information, and retain some useful header information.

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",  

  }

#Send get request

response = requests.get(url,headers = headers)

# View the response content. response.text returns data in Unicode format.

print(response.text)

# View response code

print(response.status_code)

operation result:

 

Method 2: Get request with parameters.

import requests

url="http://127.0.0.1:8090/recruit.students/login/in?"

#Process the request header information, remove some useless header information, and retain some useful header information

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

# URL parameters

payload = {'account': 'admin','pwd':'660B8D2D5359FF6F94F8D3345698F88C'}

#Send get request

response = requests.get(url,headers = headers,params=payload)

# View the response content. response.text returns data in Unicode format.

print(response.text)

# View response code

print(response.status_code)

operation result:

 

Method 3: Post request with data=payload.

 

import requests

url="http://127.0.0.1:8090/recruit.students/login/in?"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

# URL parameters

payload = {'account': 'admin','pwd':'660B8D2D5359FF6F94F8D3345698F88C'}

#Send Post request

response = requests.post(url,headers = headers,data=payload)

# View the response content. response.text returns data in Unicode format.

print(response.text)

# View response code

print(response.status_code)

operation result:

 

These three methods all implement the login interface use case of the Education Bureau Enrollment Management System. We then print the URL after requesting the response.

http://127.0.0.1:8090/recruit.students/school/manage/index;jsessionid=13284D7E10CA9E92A443873A59D9E3A1 . From this address, we can see that when we log in, the interface redirects to http://127.0.0.1: The address 8090/recruit.students/school/manage/index  is the same as the result of our packet capture.

 

Step 4: Verify the results.

By comparing the results of running the program with the results of packet capture, the verification passes.

1.3 Test case assertions

For the assertion design of interface use cases, the client needs to send an http request and the server returns response (html content). We need to consider extracting elements in the html content as checkpoints for the use case, for example

After the login interface use case of the Education Bureau Enrollment Management System is successfully logged in, we can set up an assertion to see if the "log out" text can be obtained from the response (html content) returned by the server.

 

Step 1: First, we send a request and get the response (html content) returned by the server for analysis.

 

For further confirmation, you can copy the returned html content to EditPlus 3 for viewing.

 

The second step is to write code and make assertions.

Program implementation:

from bs4 import BeautifulSoup

import requests

url="http://127.0.0.1:8090/recruit.students/login/in?"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

# URL parameters

payload = {'account': 'admin','pwd':'660B8D2D5359FF6F94F8D3345698F88C'}

#Send get request

response = requests.get(url,headers = headers,params=payload)

# View the response content. response.text returns data in Unicode format.

html=response.text

#Create Beautiful Soup object

soup = BeautifulSoup(html,"lxml")

# Get the "Logout" text

info =soup.select('.toprighthref')[0].get_text()

#Assert, check whether the result of the get request sent by the client is as expected.

try:

    assert info == "Log out"

    print('-----pass------')

except ValueError:

print("----fail-----")

operation result:

 

Here to obtain the text information of html, we just use the BeautifulSoup introduced earlier. You can try using regular expressions or XPath.

Note: For the http request port, try not to use the corresponding status code (response.status_code) as an assertion. For example: status code (200) is considered to be a successful use case. In reality, many requests return a status code of 200, which is actually The request failed. Therefore, the conditions used to make assertions must be accurate and unique.

1.4 Design of interface test cases

Web interface testing can actually be equated to functional testing, except that the object being tested is an interface and there is no interface interaction; therefore, the method of use case design is universal.

Commonly used test methods are as follows:

1. Equivalence class division method

2. Boundary value analysis

3. Cause-and-effect diagram judgment method

4. Scenario analysis method

17.4.1 Interface test case design concerns

1. The protocol type of the interface (http or https...).

2. Interface request method (get/post...).

3. Whether the parameters are required.

4. Is there any correlation between parameters?

5. Parameter value range.

6. Business rules.

17.4.2 Interface test case design ideas

1)    Priority--for all interfaces.

1. An interface exposed to the outside world, because this interface is usually called by a third party.

2. Core functional interface for internal calls in the system.

3. Provides interfaces for calling non-core functions within the system.

2)    Priority--for a single interface.

1. Forward use cases are tested first, followed by reverse use cases (usually, not absolutely).

2. Whether the prerequisites are met > whether the parameters carry default parameter values ​​> whether the parameters are required > whether there is a correlation between parameters > parameter data type restrictions > data range value restrictions of the parameter data type itself.

17.4.3 Interface test case design analysis

Generally, the following aspects need to be considered when designing interface test cases:

1. Whether the prerequisites are met

Some interfaces need to meet preconditions before they can successfully obtain data. Commonly, you need to log in with Token.

Reverse use case:

Design 0~n use cases based on whether the preconditions are met (assumed to be n conditions).

2. Whether to carry default value parameters.

Positive use case:

Do not fill in any parameters with default values ​​and do not pass parameters. All required parameters must be filled in with correct and existing "regular" values. Leave the others blank and design a use case.

3. Business rules and functional requirements.

Here, based on the actual situation and combined with the interface parameter description, it may be necessary to design n forward use cases and reverse use cases.

4. Whether the parameters are required.

Reverse use case:

For each required parameter, a reverse use case is designed with the parameter value being empty.

5. Is there any correlation between parameters?

Some parameters have a mutually restrictive relationship with each other.

Reverse use case:

Depending on the actual situation, 0~n use cases may need to be designed.

6. Parameter data type restrictions.

Reverse use case:

For each parameter, design a reverse use case in which the parameter value type does not match.

7. The data range value limit of the parameter data type itself.

Positive use case:

For all parameters, design a positive use case in which the parameter value of each parameter is the maximum value within the data range.

Reverse use case:

For each parameter (assuming n), design n reverse use cases in which the parameter value of each parameter exceeds the maximum value of the data range.

For each parameter (assuming n), design n reverse use cases in which the parameter value of each parameter is less than the minimum value of the data range.

If the above aspects are taken into consideration, the following aspects can basically be covered:

Main process test case: normal main process function verification.

Branch flow test case: normal branch flow function verification.

Exception flow test case: exception fault tolerance verification.

17.4.4 Interface test case design template

 

Note: The template will be shared to the network disk, and everyone can download it from the network disk.

1.5 Education Bureau Enrollment Management System-Interface Test Case

1.5.1 Test Case 1-Add a new school

Use case steps:

1. Log in to the Education Bureau Enrollment Management System

2. Create a new school (school name: tschool; school type: primary school; permission to admit students: check; remarks: create a new school)

3. After filling in, click Submit.

 

Capture packets through fiddler.

 

We can collect relevant information about the interface:

[Request method]:POST

【URL】: http://127.0.0.1:8090/recruit.students/school/manage/addSchoolInfo

【headers】:

{"Connection": "keep-alive",

"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

"Referer": "http://127.0.0.1:8090/recruit.students/school/manage/index",}

【data】:

{"schoolName":"t_school",

"listSchoolType[0].id": "2",

"canRecruit":"" 1,

"remark":"create a new school",}

After the school is successfully created, we can view the newly created data through the school column.

The school list is another interface: http://127.0.0.1:8090/recruit.students/school/manage/schoolInfoList

 

After analysis, we can write interface test cases.

Program implementation:

import requests

import json

from urllib import parse

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless header information, and retain some useful header information

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

response = requests.get(url_login ,headers = headers)

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers1 = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

r1 = requests.get(url_login,headers = headers1)

#print(r1.text)

# New school

url_create_school="http://127.0.0.1:8090/recruit.students/school/manage/addSchoolInfo"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers2 = {"Connection": "keep-alive",

"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

"Referer": "http://127.0.0.1:8090/recruit.students/school/manage/index",

"X-Requested-With": "XMLHttpRequest",

"Cookie": "JSESSIONID=09CD90A3357DEBD4F3B0F2CF3B387DCA",

}

formdata = {

"schoolName":"t_school2",

"listSchoolType[0][id]":"2",

"canRecruit":"1",

"remark":"create a new school_2",

}

# Transcode via urlencode()

postdata = parse.urlencode(formdata)

print(postdata)

#Create a session object to save cookie values.

ssion = requests.session()

# Send a request with username and password, obtain the cookie value after login, and save it in the session.

r2 = ssion.post(url_create_school,headers = headers2,data=postdata)

html = r2.text

print(html)

# View response code

print(r2.status_code)

operation result:

 

Test case 2: Query schools from the school list.

Use case steps:

1. Log in to the Education Bureau Enrollment Management System

2. Search the school from the school list (school name: t_school)

3. Click query.

 

Use fiddler to capture packets

 

Code:

import requests

import json

from urllib import parse

import requests

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless header information, and retain some useful header information

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

response = requests.get(url_login ,headers = headers)

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers1 = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

r1 = requests.get(url_login,headers = headers1)

#print(r1.text)

# Query school

url_find_school="http://127.0.0.1:8090/recruit.students/school/manage/schoolInfoList"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers2 = {""

"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0",

"Accept": "application/json, text/javascript, */*; q=0.01",

"Referer": "http://127.0.0.1:8090/recruit.students/school/manage/index",

"X-Requested-With": "XMLHttpRequest",

"Cookie": "JSESSIONID=09CD90A3357DEBD4F3B0F2CF3B387DCA",

"Connection": "keep-alive",

}

formdata = {

"schoolName":"t_school",

"schoolType":"0",

"page":"1",

"pageSize":"15",

}

# Transcode via urlencode()

postdata = parse.urlencode(formdata)

#Print the transcoded data

print(postdata)

#Create a session object to save the login cookie value.

ssion = requests.session()

# Send a request with username and password, obtain the cookie value after login, and save it in the session.

r2 = ssion.post(url_find_school,headers = headers2,data=postdata)

html = r2.text

print(html)

# View response code

print(r2.status_code)

operation result:

 

Test Case 3: Disable School.

 

Capture packets through fiddler.

 

Program implementation:

import requests

import json

from urllib import parse

import requests

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless header information, and retain some useful header information

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99

Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

response = requests.get(url_login ,headers = headers)

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers1 = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99

Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

r1 = requests.get(url_login,headers = headers1)

#print(r1.text)

# Query school

url_DisableSchool="http://127.0.0.1:8090/recruit.students/school/manage/enableOrDisableSchool"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers2 = {""

"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0",

"Referer": "http://127.0.0.1:8090/recruit.students/school/manage/index",

"Content-Type": "application/json",

"X-Requested-With": "XMLHttpRequest",

"Content-Length": "46",

"Cookie": "JSESSIONID=09CD90A3357DEBD4F3B0F2CF3B387DCA",

"Connection": "keep-alive",

}

#The data type of the interface is json format

formdata = {"id":"820890","disable":0,"schoolId":"251"}

# Transcode via urlencode()

postdata = parse.urlencode(formdata)

#Print the transcoded data

print(postdata)

#Create a session object to save the login cookie value.

ssion = requests.session()

# Send a request with username and password, obtain the cookie value after login, and save it in the session.

r2 = ssion.post(url_DisableSchool,headers = headers2,data=postdata)

html = r2.text

print(html)

# View response code

print(r2.status_code)

operation result:

 

Test case 4: Enable school.

Program implementation:

import requests

import json

from urllib import parse

import requests

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless header information, and retain some useful header information

headers = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

response = requests.get(url_login ,headers = headers)

# Step 1: Log in to the Education Bureau Enrollment Management System

url_login="http://127.0.0.1:8090/recruit.students/login/in?account=admin&pwd=660B8D2D5359FF6F94F8D3345698F88C"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers1 = {

    "Connection": "keep-alive",

    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",

    "Referer": "http://127.0.0.1:8090/recruit.students/login/view",

  }

#Send get request

r1 = requests.get(url_login,headers = headers1)

#print(r1.text)

# enable school

url_DisableSchool="http://127.0.0.1:8090/recruit.students/school/manage/enableOrDisableSchool"

#Process the request header information, remove some useless ones, and retain some useful header information·

headers2 = {""

"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0",

"Referer": "http://127.0.0.1:8090/recruit.students/school/manage/index",

"Content-Type": "application/json",

"X-Requested-With": "XMLHttpRequest",

"Cookie": "JSESSIONID=365D9E30F67F88F7301B32AA83C14011",

"Connection": "keep-alive",

}

#The data type of the interface is json format

formdata = {"id":"820890","disable":1,"schoolId":"251"}

# Transcode via urlencode()

postdata = parse.urlencode(formdata)

#Print the transcoded data

print(postdata)

#Create a session object to save the login cookie value.

ssion = requests.session()

# Send a request with username and password, obtain the cookie value after login, and save it in the session.

r2 = ssion.post(url_DisableSchool,headers = headers2,data=postdata)

html = r2.text

print(html)

# View response code

print(r2.status_code)

operation result:

 

[Full 200 episodes] A collection of super detailed advanced tutorials on automated testing of Python interfaces, truly simulating the actual combat of enterprise projects.

Guess you like

Origin blog.csdn.net/dq565/article/details/133170971