Contents: Guide
-
- foreword
- 1. From entry to mastery of Python programming
- 2. Interface automation project actual combat
- 3. Actual Combat of Web Automation Project
- 4. Actual Combat of App Automation Project
- 5. Resume of first-tier manufacturers
- 6. Test and develop DevOps system
- 7. Commonly used automated testing tools
- Eight, JMeter performance test
- 9. Summary (little surprise at the end)
foreword
Generally, the company's external interfaces will use sign signatures to provide different apikeys for different customers, which can improve the security of interface requests and avoid random requests by modifying request parameters after being captured.
Interface sign signature
Take a login interface request as an example, the following interface captures packet information, and the signature rules of sign are as follows
The first step is to concatenate the string, first remove the sign parameter itself, and then remove the parameter p3 whose value is empty, leaving p2=v2&p1=v1&method=cancel&pn=vn, and then sort in ascending order of the parameter name characters, method=cancel&p1=v1&p2=v2&
pn =vn.
The second step is to concatenate the parameter name and value, and finally get methodcancelp1v1p2v2pnvn. The
third step is to add the verification key apikey after the above concatenated string. We assume it is abc and get the new string methodcancelp1v1p2v2pnvnabc.
Fourth step, and then convert the string to lowercase for md5 calculation, assuming that the result is abcdef, this value is the signature value of sign.
Note: Before calculating md5, please ensure that the string encoding of the interface is consistent with that of the accessing party. For example, utf-8 encoding or GBK encoding is used uniformly. If the encoding methods are inconsistent, the calculated signature will fail to verify.
POST http://127.0.0.1:8000/api/v3/login HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json
Host: 127.0.0.1:8000
Content-Length: 111
{
"username": "test",
"password": "123456",
"sign": "1aca01806e93bb408041965a817666af"
}
HTTP/1.1 200 OK
Date: Sat, 26 Oct 2019 03:38:31 GMT
Server: WSGIServer/0.2 CPython/3.6.0
Content-Type: application/json
Vary: Accept, Cookie
Allow: POST, OPTIONS
X-Frame-Options: SAMEORIGIN
Content-Length: 109
{
"code": 0, "msg": "login success!", "username": "test", "token": "a76ba3b8fcbdff82f6a94e5ad5bf8fb934192e5f"}
Implement sign signature
Write the pre_sign function in conftest.py to preprocess the body part of the request
import hashlib
from pytest_yaml_yoyo import my_builtins
def sign_body(body: dict) -> str:
"""对body 签名"""
key = "12345678" # 接口项目的开发提供
# 去掉sign 和值为空的
new_body = [''.join(item) for item in body.items() if item[0] != 'sign' and item[1] != '']
# print(new_body)
# 做排序
new_body.sort()
# 拼接
# print(new_body)
str_body = ''.join(new_body) + key
# print(str_body)
# md5加密
def jiamimd5(src: str):
"""md5加密"""
m = hashlib.md5()
m.update(src.encode('UTF-8'))
return m.hexdigest()
sign = jiamimd5(str_body)
return sign
def pre_sign(req: dict):
print(f'请求预处理:{
req}')
sign = sign_body(req.get('json'))
req['json']['sign'] = sign
print(f'处理后的req数据:{
req}')
my_builtins.pre_sign = pre_sign
The req parameter in the pre_sign function corresponds to the request parameter in the yaml use case, which is a dictionary type of data
test_sign_login.yml use case content
config:
name: 登录
hooks:
request: ['pre_sign']
test_login:
name: 登录
request:
method: POST
url: /api/v3/login
json:
username: test8
password: "123456"
validate:
- eq: [body.code, 0]
Run the use case
pytest test_sign_login.yml
run log
test_sign_login.yml::test_login
---------------------------------------------------- live log call -----------------------------------------------------
2023-06-08 09:45:11 [INFO]: 执行文件-> test_sign_login.yml
2023-06-08 09:45:11 [INFO]: base_url-> http://127.0.0.1:8200
2023-06-08 09:45:11 [INFO]: config variables-> {
}
2023-06-08 09:45:11 [INFO]: 运行用例-> test_login
请求预处理:{
'method': 'POST', 'url': '/api/v3/login', 'json': {
'username': 'test8', 'password': '123456'}}
处理后的req数据:{
'method': 'POST', 'url': '/api/v3/login', 'json': {
'username': 'test8', 'password': '123456', 'sign': '
65faa7273d552aaedda3abdd1fe5c865'}}
2023-06-08 09:45:11 [INFO]: -------- request info ----------
2023-06-08 09:45:11 [INFO]: yml raw -->: {
'method': 'POST', 'url': '/api/v3/login', 'json': {
'username': 'test8', 'passw
ord': '123456', 'sign': '65faa7273d552aaedda3abdd1fe5c865'}}
2023-06-08 09:45:11 [INFO]: method -->: POST
2023-06-08 09:45:11 [INFO]: url -->: /api/v3/login
2023-06-08 09:45:11 [INFO]: headers -->: {
'User-Agent': 'python-requests/2.30.0', 'Accept-Encoding': 'gzip, deflate', 'A
ccept': '*/*', 'Connection': 'keep-alive'}
2023-06-08 09:45:11 [INFO]: json -->: {
"username": "test8", "password": "123456", "sign": "65faa7273d552aaedda3abdd1f
e5c865"}
2023-06-08 09:45:11 [INFO]: ------ response info 200 OK ------
2023-06-08 09:45:11 [INFO]: 耗时 <--: 0.207054s
2023-06-08 09:45:11 [INFO]: url <--: http://127.0.0.1:8200/api/v3/login
2023-06-08 09:45:11 [INFO]: headers <--: {
'Date': 'Thu, 08 Jun 2023 01:45:11 GMT', 'Server': 'WSGIServer/0.2 CPython/3.6
.8', 'Content-Type': 'application/json', 'Allow': 'POST, OPTIONS', 'X-Frame-Options': 'SAMEORIGIN', 'Content-Length': '11
0', 'Vary': 'Cookie'}
2023-06-08 09:45:11 [INFO]: cookies <--: {
}
2023-06-08 09:45:11 [INFO]: raw text <--: {
"code": 0, "msg": "login success!", "username": "test8", "token": "045acf05c42
2ad8a40e2309ecb8de830d664e50c"}
2023-06-08 09:45:11 [INFO]: validate 校验内容-> [{
'eq': ['body.code', 0]}]
2023-06-08 09:45:11 [INFO]: validate 校验结果-> eq: [0, 0]
2023-06-08 09:45:11 [INFO]: export 导出全局变量:{
}
PASSED
As can be seen from the running results, although the use case does not pass the sign parameter, the request hook in the hooks preprocesses the request parameters to realize the automatic addition of the sign parameter to the dynamic signature.
请求预处理:{
'method': 'POST', 'url': '/api/v3/login', 'json': {
'username': 'test8', 'password': '123456'}}
处理后的req数据:{
'method': 'POST', 'url': '/api/v3/login', 'json': {
'username': 'test8', 'password': '123456', 'sign': '
65faa7273d552aaedda3abdd1fe5c865'}}
The use of hooks parameters in the use case
The previous example is to put the hooks parameter in config, and the scope of action is to automatically call the preprocessing function for each request in the current yaml use case file.
config:
name: 登录
hooks:
request: ['pre_sign']
If you only preprocess a single request, you can put the hooks parameter into the request parameter of the interface
config:
name: 登录
test_login:
name: 登录
request:
method: POST
url: /api/v3/login
json:
username: test8
password: "123456"
hooks:
request: ['pre_sign']
validate:
- eq: [body.code, 0]
In this way, the scope of hooks is only for a single interface request.
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
2. Interface automation project actual combat
3. Actual Combat of Web Automation Project
4. Actual Combat of App Automation Project
5. Resume of first-tier manufacturers
6. Test and develop DevOps system
7. Commonly used automated testing tools
Eight, JMeter performance test
9. Summary (little surprise at the end)
Only by doing our best can we surpass ourselves and let our dreams soar. No matter how dense the thorns ahead are, we must bravely go through and chase the stars and seas in our hearts. Persistence, success will belong to those who dare to struggle.
Only by doing our best can we reach the other side of glory; only by persevering can we create our own miracles; as long as we have dreams in mind, every step is a brave starting point towards success. Believe in yourself and keep fighting!
Every effort is an opportunity, and every persistence is a hope. Don't be afraid to fail, success requires courage and determination. Only by constantly striving can we welcome a bright future. Believe in yourself, you can do it!