1. 简介
• 介绍本篇文章的内容:使用 pytest 进行异步验证码识别和登录的自动化处理。
2. 环境准备
• 需要的库和工具:pytest, pytest-asyncio, httpx, ddddocr, PIL。
3. CaptchaLogin 类的实现
import ddddocr
from PIL import Image
from io import BytesIO
from common.logging_util import ERROR,DEBUG
class CaptchaLogin:
def __init__(self):
self.ocr = ddddocr.DdddOcr()
# 获取并识别验证码,最多重试10次
async def fetch_and_recognize_captcha(self, client, max_retries=10):
for attempt in range(max_retries):
# 发送请求获取验证码图片
captcha_response = await client.get("https://www.xxxx.com/rest/user/captcha", timeout=10)
# 读取响应内容并转换为图像
image = Image.open(BytesIO(captcha_response.content))
# 保存验证码图片到本地
image.save("captcha.png")
DEBUG(f"验证码图片已保存为 captcha.png (尝试 {attempt + 1}/{max_retries})")
# 打开保存的验证码图片并读取为字节
with open("captcha.png", "rb") as f:
image_bytes = f.read()
# 使用 ddddocr 进行验证码识别
image_token = self.ocr.classification(image_bytes).strip()
DEBUG(f"识别出的验证码: {image_token}")
# 如果识别成功,则返回识别的验证码
if image_token:
return image_token
DEBUG("识别验证码失败或验证码为空,重试中...")
# 达到最大重试次数仍未成功识别,打印错误信息并返回 None
return None
# 发送登录请求,最多重试10次
async def attempt_login(self, client, max_retries=10):
image_token = await self.fetch_and_recognize_captcha(client)
if not image_token:
ERROR("验证码接口错误")
return None
for attempt in range(max_retries):
# 准备登录请求的数据
login_data = {
"username": "admin",
"password": "admin",
"imageToken": image_token
}
DEBUG(f"发送的登录数据: {login_data} (尝试 {attempt + 1}/{max_retries})")
headers = {'Content-Type': 'application/json'}
# 发送登录请求
login_response = await client.post("https://www.xxxx.com/rest/user/login", json=login_data, headers=headers, timeout=10)
DEBUG(f"登录响应状态码: {login_response.status_code}")
response_json = login_response.json()
DEBUG(f"登录响应 JSON: {response_json}")
# 检查响应是否表示登录成功
if response_json.get('code') == 200:
# 登录成功,返回 token
return response_json.get('data', {}).get('token')
# 如果响应消息表示验证码错误,则重新获取验证码并重试
if response_json.get('msg', '').lower() in ['验证码错误', '验证码无效']:
DEBUG("验证码错误,重新获取验证码...")
image_token = await self.fetch_and_recognize_captcha(client)
if not image_token:
break
else:
DEBUG("登录失败,重试中...")
# 达到最大重试次数仍未成功登录,打印错误信息并返回 None
ERROR("登录验证码有误,请检查")
return None
4. 编写 conftest.py 文件
conftest.py 是 pytest 测试框架中的一个特殊文件,用于定义共享的 fixture 和测试配置。它在 pytest 项目中起到以下几个关键作用:
主要作用
定义全局或局部的 Fixture:
• conftest.py 文件允许你定义 fixture,这些 fixture 可以在同一目录及其子目录中的所有测试文件中共享使用。通过这种方式,可以避免在每个测试文件中重复定义相同的 fixture。
• 例如,数据库连接、配置初始化等常见的准备工作,可以通过 fixture 在 conftest.py 中进行定义。
实现测试的自动发现和配置:
• pytest 会自动发现并加载 conftest.py 文件中的配置。这使得你可以通过简单的目录结构管理复杂的测试项目,而无需在每个测试文件中进行额外的配置。
• 例如,可以在 conftest.py 中配置命令行选项、钩子函数等,来影响测试的执行方式。
管理跨测试的共享状态:
• conftest.py 文件可以管理跨测试的共享状态,例如在多个测试用例之间共享一个数据库会话,或者在测试开始和结束时执行特定的操作(如启动和关闭服务)。
• 这对于需要在多次测试运行之间保持某种状态的场景非常有用。
示例代码
以下是一个 conftest.py 文件的示例,它定义了一个登陆并获取token,并在会话范围内共享:
import asyncio
import pytest
import httpx
from common.captch_login import CaptchaLogin
from common.cache_util import local_cache
from common.logging_util import INFO,DEBUG,WARNING,ERROR
@pytest.fixture(scope="session", autouse=True)
def work_login_init():
"""
Fixture,负责整体登陆流程控制:获取并识别验证码,然后使用识别的验证码尝试登录。
如果登录成功,保存 token;否则保存 None。
"""
# 创建 CaptchaLogin 类的实例
captcha_login = CaptchaLogin()
async def login_task():
"""
异步任务,负责使用 httpx.AsyncClient 发送请求以获取并识别验证码,然后尝试登录并保存 token。
"""
# 使用 httpx.AsyncClient 创建异步 HTTP 客户端
async with httpx.AsyncClient() as client:
# 调用 captcha_login 实例的 attempt_login 方法进行登录尝试
token = await captcha_login.attempt_login(client=client)
if token:
# 如果成功获取到 token,则将其保存到本地缓存
local_cache.set_data('token', token)
DEBUG(f"获得的 token: {token}")
else:
# 如果未成功获取到 token,则将 None 保存到本地缓存
local_cache.set_data('token', None)
ERROR("获取 token 失败")
5. 运行测试
在运行接口自动化初始,pytest会先运行conftest中的代码,上述代码介绍了获取登陆token,并存到缓存中.
6. 总结
在自动化测试中,验证码识别和登录通常是一个挑战。特别是在需要处理异步请求的情况下,测试代码的编写变得更加复杂。本文将详细介绍如何使用 pytest 结合 pytest-asyncio 插件,实现一个完整的异步验证码识别和登录的自动化测试流程。通过分步讲解,你将学习如何构建一个能够自动获取、识别验证码并完成登录的测试框架。希望本文能为你的自动化测试提供有价值的参考。