验证码是 QA 流水线里最容易被忽略的阻塞点:注册、登录或下单流程一旦挂了 reCAPTCHA,回归测试往往靠人肉点验证码,或者干脆跳过。把 CaptchaAI 接入测试脚本,就能让这类流程重新纳入自动化测试范围,不用改动被测页面本身。
哪些 QA 场景离不开验证码自动识别
下面几类测试最常被验证码卡住,也是接入 CaptchaAI 收益最明显的场景:
- 回归测试——确认部署后表单依然可用
- 端到端测试——跑通完整用户旅程
- 负载测试——大规模模拟真实验证码流量
- 跨浏览器测试——验证组件在不同浏览器下正常渲染
- 无障碍测试——覆盖残障用户的替代交互流程
举例:某跨境电商团队的预发布环境同时挂载 reCAPTCHA v2(海外用户)和 GeeTest(极验,国内落地页)。reCAPTCHA 依赖 Google 托管脚本,境内网络访问常超时,团队因此把用例拆进独立 CI job。
接入前先算清楚:验证码测试的成本怎么控制
验证码识别本身有成本,套件一大容易被忽略。开始写代码前先理清控制点:
- 用 staging 环境测试——难度通常更低
- 按计划运行,而非每次 push——降低调用成本
- 确认 flaky 的用例缓存结果——避免重复识别
- 用环境变量本地跳过——节省开发成本
- 验证码用例集中放进专用 CI job——单独控制成本
这些手段可以叠加——先按计划跑,稳定后再引入缓存和标签拆分。
用 Pytest 封装可复用的验证码识别逻辑
把验证码识别逻辑封装成 helper 类,测试用例只管拿 token。CaptchaTestHelper 通过 in.php / res.php 完成提交与轮询,再用 fixture 注入测试类:
import pytest
import requests
import time
class CaptchaTestHelper:
"""Helper for solving CAPTCHAs in test environments."""
def __init__(self, api_key):
self.api_key = api_key
def solve_recaptcha(self, sitekey, pageurl, timeout=120):
"""Solve reCAPTCHA and return token."""
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
}, timeout=30)
result = resp.json()
assert result.get("status") == 1, f"Submit failed: {result}"
task_id = result["request"]
deadline = time.time() + timeout
time.sleep(10)
while time.time() < deadline:
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key, "action": "get",
"id": task_id, "json": 1,
}, timeout=15)
data = resp.json()
if data.get("status") == 1:
return data["request"]
if data["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve error: {data['request']}")
time.sleep(5)
raise TimeoutError("CAPTCHA solve timeout")
@pytest.fixture(scope="session")
def captcha_helper():
"""Provide CaptchaAI helper for test session."""
import os
api_key = os.environ.get("CAPTCHAAI_API_KEY")
if not api_key:
pytest.skip("CAPTCHAAI_API_KEY not set")
return CaptchaTestHelper(api_key)
class TestLoginFlow:
"""Test login flow behind reCAPTCHA."""
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
LOGIN_URL = "https://staging.example.com/qa-login"
def test_login_with_valid_credentials(self, captcha_helper):
"""Verify login succeeds with valid creds and solved CAPTCHA."""
token = captcha_helper.solve_recaptcha(self.SITEKEY, self.LOGIN_URL)
assert token and len(token) > 100
resp = requests.post(self.LOGIN_URL, data={
"username": "test_user",
"password": "test_pass",
"g-recaptcha-response": token,
})
assert resp.status_code == 200
assert "Welcome" in resp.text
def test_login_with_invalid_credentials(self, captcha_helper):
"""Verify login fails gracefully with bad creds but valid CAPTCHA."""
token = captcha_helper.solve_recaptcha(self.SITEKEY, self.LOGIN_URL)
resp = requests.post(self.LOGIN_URL, data={
"username": "wrong_user",
"password": "wrong_pass",
"g-recaptcha-response": token,
})
assert resp.status_code in (200, 401)
assert "Invalid" in resp.text or "error" in resp.text.lower()
def test_login_without_captcha_fails(self):
"""Verify login rejects submissions without CAPTCHA."""
resp = requests.post(self.LOGIN_URL, data={
"username": "test_user",
"password": "test_pass",
})
assert resp.status_code in (400, 403, 422)
TestLoginFlow 覆盖三种情况:凭证和验证码都对、验证码对但凭证错、缺验证码字段,确认登录逻辑和验证码校验互不干扰。
用 Selenium 跑通带验证码的端到端流程
端到端测试面对真实渲染的验证码组件。下面的模式从 DOM 读取 data-sitekey,调用 CaptchaAI 解决后把 token 写回表单,再触发 data-callback:
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
@pytest.fixture
def browser():
"""Create browser for testing."""
options = webdriver.ChromeOptions()
options.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(options=options)
yield driver
driver.quit()
class TestRegistrationFlow:
"""Test registration form with CAPTCHA."""
REG_URL = "https://staging.example.com/register"
def test_registration_form_submits(self, browser, captcha_helper):
"""Full registration flow with CAPTCHA solving."""
browser.get(self.REG_URL)
# Fill form
browser.find_element(By.ID, "email").send_keys("[email protected]")
browser.find_element(By.ID, "password").send_keys("SecurePass123!")
browser.find_element(By.ID, "confirm_password").send_keys("SecurePass123!")
# Extract sitekey from page
captcha_div = browser.find_element(By.CSS_SELECTOR, ".g-recaptcha")
sitekey = captcha_div.get_attribute("data-sitekey")
# Solve via API
token = captcha_helper.solve_recaptcha(sitekey, browser.current_url)
# Inject token
browser.execute_script("""
document.querySelector('[name="g-recaptcha-response"]').value = arguments[0];
""", token)
# Trigger callback if needed
callback = captcha_div.get_attribute("data-callback")
if callback:
browser.execute_script(f"window['{callback}'](arguments[0]);", token)
# Submit
browser.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
# Verify success
WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".success-message"))
)
def test_captcha_renders_on_page(self, browser):
"""Verify CAPTCHA widget loads on registration page."""
browser.get(self.REG_URL)
captcha = WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".g-recaptcha, iframe[src*='recaptcha']"))
)
assert captcha.is_displayed()
test_captcha_renders_on_page 单独验证组件能否加载——先挂了就是页面问题,不用怀疑识别逻辑。
给验证码测试单独打标签,控制流水线范围
验证码识别有网络往返,耗时几秒到几十秒,混进主干套件会拖慢反馈。用 pytest 自定义 marker 把用例单独标出来:
# conftest.py
import os
# Mark tests that need CAPTCHA solving
def pytest_configure(config):
config.addinivalue_line(
"markers", "captcha: tests requiring CAPTCHA solving (may be slow)"
)
# pytest.ini or pyproject.toml
"""
[tool.pytest.ini_options]
markers = [
"captcha: tests requiring CAPTCHA solving (may be slow)",
]
"""
只跑验证码用例:
pytest -m captcha -v
跳过验证码,走快速通道:
pytest -m "not captcha" -v
接入前的落地检查
接入 CaptchaAI 前,建议先自查这几项:
| 检查项 | 目的 |
|---|---|
| Helper 是否用 fixture 注入 | 减少重复轮询代码 |
| 是否用 marker 分组 | 主干套件不被拖慢 |
| 单元测试是否已 mock 验证码 | 识别只留给集成/端到端层 |
| 是否确认 staging 验证码难度 | 避免与生产环境不一致 |
确认后再合入主干 CI。
常见问题
运行验证码测试大概要花多少钱?
reCAPTCHA v2 单次识别约 $0.003,50 个用例的套件跑一次约 $0.15,按每天一次算,月成本约 $4.50,可直接编进 CI 预算。
验证码识别超时或失败,会不会拖出一堆"假失败"的用例?
会,这是常见的 flaky 来源。建议设置合理超时(示例 120 秒),失败时抛明确错误,并对确认是网络抖动的用例缓存结果。
要不要给验证码测试单独建一条 CI 流水线?
建议单独建:验证码识别耗时比单元测试高一个量级。用 captcha marker 分组,主干只跑 not captcha,验证码用例走独立 job。
单元测试该不该直接调用验证码识别 API?
不建议:单元测试应 mock 验证码返回值;只有集成测试和端到端测试对接真实环境时,才需要调用 CaptchaAI 拿真实 token。
预发布环境里同时有 reCAPTCHA 和 GeeTest,测试脚本要分别处理吗?
是的:reCAPTCHA v2 提交 googlekey + pageurl,GeeTest v3 提交 gt、challenge 等参数,返回字段也不同。项目里通常按类型各封装一个 helper,公用轮询逻辑。
相关指南
自动化你的 QA 流程——把 CaptchaAI 接入你的测试流水线。