httprunner version: 4.3.5
HttpRunner v4 introduces a new plugin mechanism, currently supporting custom function implementations in both Python and Go languages. For Go code, it must be compiled into a debugtalk.bin file. The plugin file debugtalk.xx must be placed in the project root directory.
Next, we will discuss how to implement any complex business logic testing using custom functions in Python.
The plugin-python allows for custom functions to be written in Python, requiring only the creation of the debugtalk.py file in the project root directory, with no additional compilation needed. Additionally, using hrp run/boom is compatible with the syntax from versions prior to v4.0. Note: When testing with hrp, it generates a .debugtalk_gen.py file that can be directly called based on the debugtalk.py file; please do not edit this file.
Testing Scenario: In the login API test, the password is transmitted in an encrypted format, so we need to encrypt the password when passing parameters to the API. Here, we encapsulate our encryption method which calls the third-party module: pycryptodome, and the method requires two parameters: the password and the key.
1. Encryption Algorithm, Path: tools.aes_encrypt_decrypt.py
# Standard library import
import base64
# Third-party module import
from Crypto.Cipher import AES
class Encrypt:
"""
Use AES-CBC symmetric encryption algorithm to encrypt the password, padding mode is PKCS7Padding
"""
def __init__(self, key, iv):
self.key = key.encode('utf-8')
self.iv = iv.encode('utf-8')
# @staticmethod
def pkcs7padding(self, text):
"""Plaintext uses PKCS7 padding """
bs = 16
length = len(text)
bytes_length = len(text.encode('utf-8'))
padding_size = length if (bytes_length == length) else bytes_length
padding = bs - padding_size % bs
padding_text = chr(padding) * padding
self.coding = chr(padding)
return text + padding_text
def aes_encrypt(self, content):
""" AES encryption """
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
# Process plaintext
content_padding = self.pkcs7padding(content)
# Encrypt
encrypt_bytes = cipher.encrypt(content_padding.encode('utf-8'))
# Re-encode
result = str(base64.b64encode(encrypt_bytes), encoding='utf-8')
return result
def aes_decrypt(self, content):
"""AES decryption """
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
content = base64.b64decode(content)
text = cipher.decrypt(content).decode('utf-8')
return text.rstrip(self.coding)
2. Define a custom function in debugtalk.py to introduce the encryption algorithm and return the encrypted password.
from tools.aes_encrypt_decrypt import Encrypt
def get_password(target_str: str, ace_key):
"""
Use AES-CBC symmetric encryption algorithm to encrypt the password
"""
ace = Encrypt(key=ace_key, iv=ace_key)
return ace.aes_encrypt(target_str)
3. Call the custom function in the YAML test case to return the encrypted password
config:
name: "Login API"
verify: False
base_url: "https://gitlink.org.cn"
headers:
content-type: "application/json"
variables:
o_pwd: ****1234
o_key: **c9**********c1
teststeps:
-
name: Send login request
request: # request API related parameters
method: POST
url: /api/accounts/login.json
body:
autologin: 0
login: floraachy
password: ${get_password($o_pwd,$o_key)}
validate: # assertions
- eq: ["status_code", 200]
- eq: ["body.login", '${user}']
Common Pitfalls
- When third-party dependencies are introduced in debugtalk, calling custom functions fails, leading to hrp execution failure. During hrp execution, it uses the C:\Users\username.hrp\venv virtual environment, and the failure occurs because the third-party dependency was not installed in this virtual environment.
There are two solutions (source: https://github.com/httprunner/httprunner/discussions/1341):
Use the python3 in the Scripts directory to download the third-party dependency, path reference: C:\Users\username.hrp\venv\Scripts\python3 install pycryptodome
Install directly on the testing machine: pip install pycryptodome, then change the include-system-site-packages in the pyvenv.cfg file of the virtual environment from false to true.
Path reference: C:\Users\username.hrp\venv\pyvenv.cfg Modify content: include-system-site-packages = true
2. If the password contains special characters, calling the custom function fails, leading to hrp execution failure.
Solution: Treat the password as a global variable, and then directly use the global variable as a parameter in the custom function.
# ---- Complete YAML test case reference above-------
# Treat the password as a global variable
variables:
o_pwd: +=-===@123
o_key: 23333333333333
# In the custom function, directly use the global variable as a parameter
password: ${get_password($o_pwd,$o_key)}
Note: Here, when introducing global variables in the custom function, only variable names can be used, and cannot use {variable name}, otherwise execution will also report an error.