CAPTCHA korumalı bir form uç noktasını test etmek için tarayıcı açmanıza gerek yok. Token'ı CaptchaAI API'si üzerinden alın, istek gövdesine ekleyin ve doğrudan arka uca POST edin — testleriniz CI/CD hattında headless çalışır. Bu rehber, reCAPTCHA v2, reCAPTCHA v3 ve Cloudflare Turnstile korumalı uç noktalar için tekrarlanabilir bir test paketini Python ile nasıl kuracağınızı gösterir.
Tarayıcı sürücüsü (Selenium, Playwright) üzerinden test etmek yavaştır, kırılgandır ve CI ortamında bakımı pahalıdır: sayfa açılır, JavaScript yüklenir, widget render edilir ve tıklama simüle edilir. Oysa gerçekte test etmek istediğiniz şey arka uçtur — sunucunun token'ı doğru doğrulayıp doğrulamadığı.
Token'ı API ile üretip isteğe koyduğunuzda, tarayıcı katmanını tamamen atlar ve testi bir HTTP çağrısına indirgersiniz. Bu, hem çalışma süresini saniyelere düşürür hem de headless bir runner'da hiçbir tarayıcı bağımlılığı olmadan koşmanızı sağlar.
CAPTCHA korumalı uç nokta testi ne zaman gerekir
Bu yaklaşım, bir formu "kullanıcı gibi" doldurmayı değil, form gönderiminin ardındaki API sözleşmesini doğrulamayı hedefler. Dört tipik durumda işe yarar:
- Arka uç doğrulama testi: Sunucunun token'ı gerçekten Google veya Cloudflare'e karşı doğruladığını, geçersiz bir değeri sessizce kabul etmediğini teyit edin. Bu, listedeki en kritik testtir — çünkü doğrulamayı atlayan bir arka uç, sahte gönderimlere sonuna kadar açıktır.
- Yük testi: CAPTCHA korumalı uç noktaya çok sayıda geçerli istek göndererek davranışını, kuyruk süresini ve hata oranını gözlemleyin.
- Entegrasyon testi: Form gönderim API'lerini CI/CD hattında, her sürümden önce otomatik çalıştırarak bir regresyonun üretime sızmasını engelleyin.
- Hata yanıtı testi: Geçersiz veya süresi dolmuş token'lar için uç noktanın 4xx döndürüp anlamlı bir hata mesajı verdiğini doğrulayın.
Test paketi üç senaryoyu birlikte koşar: geçerli token (gönderim başarılı olmalı), geçersiz token (uç nokta reddetmeli) ve eksik token (uç nokta reddetmeli). Bu üçlü, hem mutlu yolu hem de arka ucun güvenlik davranışını tek geçişte kapsar.
Test akışı: dört adımda çöz, kur, gönder, doğrula
┌──────────┐ ┌────────────┐ ┌──────────────┐ ┌──────────────┐
│ Solve │────▶│ Build │────▶│ POST to │────▶│ Validate │
│ CAPTCHA │ │ Request │ │ Endpoint │ │ Response │
│ (API) │ │ Payload │ │ │ │ │
└──────────┘ └────────────┘ └──────────────┘ └──────────────┘
Çoğu uç nokta testi için tarayıcıya gerek yoktur. Akış dört adımdan oluşur:
- Çöz — CaptchaAI API'sine görevi gönderip token'ı alın.
- Kur — Token'ı form verisiyle birlikte istek gövdesine yerleştirin.
- Gönder — İsteği doğrudan arka uç uç noktasına POST edin.
- Doğrula — Durum kodunu ve yanıt gövdesini beklenen sonuçla karşılaştırın.
Token'ların kısa bir geçerlilik süresi vardır. Çözme ile gönderme arasında dakikalarca beklerseniz, geçerli bir token bile "reddedildi" sonucu verebilir — bu, uç noktanın hatası değil, testin zamanlamasıdır.
Python ile uç nokta test aracını kurma
Araç iki parçadan oluşur. Birincisi, CaptchaAI API'sinden token üreten TokenProvider; ikincisi, bu token'ı kullanarak uç noktayı çeşitli senaryolarla sınayan EndpointTester. Sorumlulukları ayırmak, token üretim mantığını değiştirmeden yeni test türleri eklemenizi kolaylaştırır.
CAPTCHA token sağlayıcı
TokenProvider, in.php uç noktasına görevi gönderir, bir görev kimliği alır ve res.php üzerinden sonucu periyodik olarak sorgular. reCAPTCHA v2, reCAPTCHA v3 ve Turnstile için tek bir arayüz sunar; v3'te ek olarak action parametresini geçirir. İlk beklemeyi v3 için biraz daha uzun tutması, bu türün tipik olarak biraz daha uzun çözüm süresi almasındandır.
import time
import requests
class TokenProvider:
BASE = "https://ocr.captchaai.com"
def __init__(self, api_key):
self.api_key = api_key
def get_recaptcha_token(self, sitekey, pageurl, version="v2"):
params = {
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
}
if version == "v3":
params["version"] = "v3"
params["action"] = "submit"
return self._solve(params, initial_wait=15 if version == "v3" else 10)
def get_turnstile_token(self, sitekey, pageurl):
return self._solve({
"method": "turnstile",
"sitekey": sitekey,
"pageurl": pageurl,
})
def _solve(self, params, initial_wait=10):
params["key"] = self.api_key
params["json"] = 1
resp = requests.post(f"{self.BASE}/in.php", data=params).json()
if resp["status"] != 1:
raise Exception(resp["request"])
task_id = resp["request"]
time.sleep(initial_wait)
for _ in range(60):
result = requests.get(
f"{self.BASE}/res.php",
params={"key": self.api_key, "action": "get", "id": task_id, "json": 1},
).json()
if result["request"] == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if result["status"] == 1:
return result["request"]
raise Exception(result["request"])
raise TimeoutError("Timed out")
Uç nokta test aracı
EndpointTester, her test yapılandırmasını bir sözlük olarak alır: uç nokta URL'si, CAPTCHA türü, sitekey, pageurl, token'ın hangi alana ekleneceği (captcha_field) ve beklenen sonuç. test_endpoint mutlu yolu; test_invalid_token ve test_missing_token ise güvenlik davranışını sınar. Sonuçlar results listesinde toplanır ve report bunları okunabilir bir özete dönüştürür.
captcha_field değerinin türle eşleşmesi kritiktir; yanlış alan adı, geçerli bir token'ın bile reddedilmesine yol açar:
| CAPTCHA türü | captcha_field |
method |
|---|---|---|
| reCAPTCHA v2 | g-recaptcha-response |
userrecaptcha |
| reCAPTCHA v3 | g-recaptcha-response |
userrecaptcha |
| Cloudflare Turnstile | cf-turnstile-response |
turnstile |
import json
import time
class EndpointTester:
def __init__(self, api_key):
self.token_provider = TokenProvider(api_key)
self.session = requests.Session()
self.results = []
def test_endpoint(self, config):
"""
config: {
"name": "test name",
"url": "endpoint URL",
"method": "POST",
"captcha_type": "recaptcha_v2" | "recaptcha_v3" | "turnstile",
"sitekey": "...",
"pageurl": "...",
"captcha_field": "g-recaptcha-response",
"payload": { ... form data ... },
"expected_status": 200,
"expected_contains": "success",
}
"""
start = time.time()
result = {"name": config["name"], "passed": False}
try:
# Get CAPTCHA token
captcha_type = config.get("captcha_type", "recaptcha_v2")
if captcha_type == "recaptcha_v2":
token = self.token_provider.get_recaptcha_token(
config["sitekey"], config["pageurl"]
)
elif captcha_type == "recaptcha_v3":
token = self.token_provider.get_recaptcha_token(
config["sitekey"], config["pageurl"], version="v3"
)
elif captcha_type == "turnstile":
token = self.token_provider.get_turnstile_token(
config["sitekey"], config["pageurl"]
)
else:
raise ValueError(f"Unknown captcha type: {captcha_type}")
# Build payload
payload = {**config.get("payload", {})}
captcha_field = config.get("captcha_field", "g-recaptcha-response")
payload[captcha_field] = token
# Submit request
method = config.get("method", "POST").upper()
headers = config.get("headers", {})
if config.get("json_body"):
resp = self.session.request(
method, config["url"], json=payload, headers=headers
)
else:
resp = self.session.request(
method, config["url"], data=payload, headers=headers
)
# Validate response
result["status_code"] = resp.status_code
result["response_length"] = len(resp.text)
result["elapsed"] = round(time.time() - start, 2)
# Check expected status
expected_status = config.get("expected_status", 200)
if resp.status_code != expected_status:
result["error"] = f"Expected {expected_status}, got {resp.status_code}"
self.results.append(result)
return result
# Check expected content
expected = config.get("expected_contains")
if expected and expected.lower() not in resp.text.lower():
result["error"] = f"Response missing: '{expected}'"
self.results.append(result)
return result
result["passed"] = True
except Exception as e:
result["error"] = str(e)
result["elapsed"] = round(time.time() - start, 2)
self.results.append(result)
return result
def test_invalid_token(self, config):
"""Test that endpoint rejects invalid CAPTCHA tokens."""
invalid_config = {**config}
invalid_config["name"] = f"{config['name']} (invalid token)"
# Override with fake token
payload = {**config.get("payload", {})}
captcha_field = config.get("captcha_field", "g-recaptcha-response")
payload[captcha_field] = "INVALID_TOKEN_12345"
start = time.time()
result = {"name": invalid_config["name"], "passed": False}
try:
resp = self.session.post(config["url"], data=payload)
result["status_code"] = resp.status_code
result["elapsed"] = round(time.time() - start, 2)
# Should reject — 4xx or error message
if resp.status_code >= 400 or "error" in resp.text.lower() or "invalid" in resp.text.lower():
result["passed"] = True
else:
result["error"] = "Endpoint accepted invalid CAPTCHA token"
except Exception as e:
result["error"] = str(e)
result["elapsed"] = round(time.time() - start, 2)
self.results.append(result)
return result
def test_missing_token(self, config):
"""Test that endpoint rejects missing CAPTCHA token."""
start = time.time()
result = {"name": f"{config['name']} (missing token)", "passed": False}
try:
payload = config.get("payload", {})
resp = self.session.post(config["url"], data=payload)
result["status_code"] = resp.status_code
result["elapsed"] = round(time.time() - start, 2)
if resp.status_code >= 400 or "captcha" in resp.text.lower():
result["passed"] = True
else:
result["error"] = "Endpoint accepted request without CAPTCHA"
except Exception as e:
result["error"] = str(e)
result["elapsed"] = round(time.time() - start, 2)
self.results.append(result)
return result
def run_suite(self, configs):
"""Run a full test suite against multiple endpoints."""
for config in configs:
self.test_endpoint(config)
self.test_invalid_token(config)
self.test_missing_token(config)
return self.report()
def report(self):
passed = sum(1 for r in self.results if r["passed"])
total = len(self.results)
lines = [f"Endpoint Tests: {passed}/{total} passed", "=" * 50]
for r in self.results:
status = "PASS" if r["passed"] else "FAIL"
elapsed = r.get("elapsed", "?")
lines.append(f" [{status}] {r['name']} ({elapsed}s)")
if r.get("error"):
lines.append(f" Error: {r['error']}")
return "\n".join(lines)
Kullanım: test paketini çalıştırma
Yapılandırma listesini tanımlayın ve run_suite ile hepsini tek seferde koşun. Aşağıdaki örnekte bir iletişim formu (reCAPTCHA v2) ve bir bülten kaydı (Turnstile) uç noktası test edilir. Her uç nokta için üç senaryonun da otomatik çalıştırıldığını unutmayın.
tester = EndpointTester("YOUR_API_KEY")
configs = [
{
"name": "Contact form submission",
"url": "https://example.com/api/contact",
"captcha_type": "recaptcha_v2",
"sitekey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
"pageurl": "https://example.com/contact",
"captcha_field": "g-recaptcha-response",
"payload": {
"name": "Test User",
"email": "test@example.com",
"message": "Automated test message",
},
"expected_status": 200,
"expected_contains": "success",
},
{
"name": "Newsletter signup",
"url": "https://example.com/api/subscribe",
"captcha_type": "turnstile",
"sitekey": "0x4AAAA...",
"pageurl": "https://example.com/newsletter",
"captcha_field": "cf-turnstile-response",
"payload": {
"email": "test@example.com",
},
"expected_status": 200,
},
]
report = tester.run_suite(configs)
print(report)
Çıktı:
Endpoint Tests: 5/6 passed
==================================================
[PASS] Contact form submission (18.5s)
[PASS] Contact form submission (invalid token) (0.3s)
[PASS] Contact form submission (missing token) (0.2s)
[PASS] Newsletter signup (14.2s)
[FAIL] Newsletter signup (invalid token) (0.3s)
Error: Endpoint accepted invalid CAPTCHA token
[PASS] Newsletter signup (missing token) (0.2s)
Bu çıktıda dikkat çeken satır, Newsletter signup (invalid token) testinin FAIL vermesidir: uç nokta geçersiz bir token'ı kabul etmiş, yani arka uç doğrulaması eksik ya da bozuk. Bu tam olarak yakalamak istediğiniz türden bir kusurdur — çünkü üretimde bu, herkesin CAPTCHA'yı hiç çözmeden form gönderebileceği anlamına gelir.
Geçerli gönderim testlerinin süresi (18,5 sn, 14,2 sn) çözüm süresini içerdiği için doğal olarak uzundur; geçersiz ve eksik token testleri ise çözüm çağrısı yapmadığı için milisaniyeler sürer.
Örnek senaryo: e-ticaret ödeme formu QA'sı
Türkiye'de bir e-ticaret ekibinde çalıştığınızı düşünün: her sürümden önce iletişim formu, üyelik kaydı ve ödeme adımındaki reCAPTCHA v2 doğrulamasının bozulmadığını kanıtlamanız gerekiyor. Üç uç noktayı tek bir test paketinde toplar, her biri için geçerli token, geçersiz token ve eksik token senaryolarını otomatik koşarsınız — böylece "arka uç, token'ı gerçekten doğruluyor mu?" sorusunu her dağıtımda tekrar sormanıza gerek kalmaz.
Test verisi üretirken gerçek müşteri bilgisi yerine test@example.com gibi sahte kayıtlar kullanın. Test ortamına taşınan kişisel veriler KVKK kapsamına girer, bu yüzden bu akışları yalnızca yetkili QA ortamlarınızla sınırlayın ve üretim veritabanından kopyalanmış gerçek kayıtlarla beslemeyin.
Sorun giderme
| Sorun | Sebep | Düzeltme |
|---|---|---|
| Geçerli token reddedildi | Token, gönderilmeden önce süresi doldu | Çözme ile gönderme arasındaki gecikmeyi azaltın |
| Geçersiz token kabul edildi | Arka uç CAPTCHA'yı doğrulamıyor | Hata kaydı açın — bu bir güvenlik açığıdır |
| Tüm isteklerde 403 | Eksik CSRF token'ı veya çerezler | Oturum çerezlerini veya CSRF başlığını ekleyin |
| JSON uç noktası form verisini reddediyor | Yanlış içerik türü | Yapılandırmada json_body: True ayarlayın |
Test paketini sağlam tutmanın yolları
Uç nokta testleri, dış bir çözüm servisine bağlı oldukları için birim testlerden daha kırılgandır. Birkaç alışkanlık, paketi CI hattında güvenilir kılar:
- Geçerli ve geçersiz senaryoları ayrı tutun. Yalnızca geçerli gönderim testleri gerçek token gerektirir; geçersiz ve eksik token testlerini bunlardan bağımsız çalıştırabilir, hızlı bir "dumansı test" olarak her commit'te koşabilirsiniz.
- Zaman aşımlarını cömert tutun. Çözüm süresi ortama ve yüke göre değişir; CI adımına dar bir zaman aşımı koymak, aslında çalışan bir uç noktayı yanlışlıkla FAIL gösterebilir.
- Sabit sırları koda gömmeyin. API anahtarını ortam değişkeni olarak geçirin;
sitekeyvepageurldeğerlerini yapılandırma dosyasında tutun. - Sonuçları raporlayın.
reportçıktısını CI günlüğüne yazdırın ki bir regresyon oluştuğunda hangi uç noktanın ve hangi senaryonun bozulduğunu tek bakışta görün.
Sık sorulan sorular (SSS)
Bu test paketi hangi CAPTCHA türlerini kapsıyor?
Örnek kod reCAPTCHA v2, reCAPTCHA v3 ve Cloudflare Turnstile korumalı uç noktaları kapsar. CaptchaAI hCaptcha ve FunCaptcha'yı desteklemez; bu türlerle korunan formlar için token üretemezsiniz.
Geçersiz veya eksik token testleri CaptchaAI bakiyenizi tüketir mi?
Hayır. Geçersiz ve eksik token senaryoları çözüm API'sini hiç çağırmaz — uç noktaya sahte ya da boş bir değer gönderirsiniz. Yalnızca geçerli gönderim testleri gerçek bir token, dolayısıyla bir çözüm çağrısı gerektirir.
Bu testleri CI/CD hattında nasıl çalıştırırım?
API anahtarınızı ortam değişkeni olarak saklayın ve test paketini headless çalıştırın; tarayıcı gerekmez. Çözüm süresini hesaba katmak için iş adımına makul bir zaman aşımı tanıyın.
reCAPTCHA v3 uç noktasını test ederken skor eşiğini nasıl doğrularım?
v3 bir puan döndürür ve arka ucunuz düşük puanlı istekleri reddetmelidir. Farklı action değerleriyle token üretip uç noktanın beklenen eşikte kabul veya ret verdiğini kontrol edin.
İlgili rehberler
Her CAPTCHA korumalı uç noktayı güvenle test edin — CaptchaAI ile başlayın.