Use Cases

QA ve Yetkili Test için CAPTCHA Çözümü

Login, kayıt ve ödeme formlarının önündeki reCAPTCHA, otomatik testlerinizi durduran ilk duvardır: Selenium ya da pytest ile akışı sürerken widget karşınıza çıkar ve senaryo orada takılır. Çözüm, CAPTCHA'yı test sırasında bir API çağrısıyla halletmektir — böylece QA hattınız gerçek doğrulama akışını, kimsenin kutucuk tıklamasına gerek kalmadan uçtan uca doğrular. Bu rehber, reCAPTCHA v2 korumalı bir akışı pytest ve Selenium ile CaptchaAI üzerinden nasıl test edeceğinizi gösterir.


CAPTCHA Testini Ne Zaman Otomatikleştirmek Gerekir?

Manuel test yalnızca yavaş değil, tekrar edilemez de: her koşuda birinin kutucuğu tıklaması gerekir. Aşağıdaki senaryolarda CAPTCHA çözümünü otomatikleştirmek, testi CI hattında insansız çalıştırmanın tek pratik yoludur.

Senaryo CaptchaAI'nin rolü
Regresyon testi Dağıtım sonrası formların hâlâ çalıştığını doğrular
Uçtan uca test Kullanıcı yolculuğunun tamamını gerçek doğrulamayla sınar
Yük testi Gerçekçi CAPTCHA akışlarını ölçekli biçimde simüle eder
Tarayıcılar arası test Widget'ın her tarayıcıda doğru yüklendiğini doğrular
Erişilebilirlik testi Engelli kullanıcılar için alternatif akışları sınar

Pytest ile CAPTCHA Çözümünü Test Akışına Bağlama

Önce yeniden kullanılabilir bir yardımcı sınıf kurun: solve_recaptcha, sitekey ve pageurl'ü CaptchaAI'ye gönderir, sonucu in.php / res.php uç noktaları üzerinden sorgular ve token'ı döndürür. Testler bu token'ı formun g-recaptcha-response alanına yazar. API anahtarını ortam değişkeninden (CAPTCHAAI_API_KEY) okuduğumuz için anahtar hiçbir zaman koda gömülmez — CI/CD için doğru yaklaşım budur.

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)

Üç senaryo birlikte doğrulamanın gerçekten iş gördüğünü kanıtlar: geçerli kimlik ve çözülmüş token başarıyla giriş yapmalı, hatalı kimlik zarifçe reddedilmeli, token olmadan yapılan gönderim ise sunucu tarafından engellenmelidir.


Selenium ile Uçtan Uca (E2E) Test Modeli

Gerçek bir tarayıcıda sitekey'i sayfadan okuyup token'ı g-recaptcha-response alanına enjekte etmek, kullanıcının gördüğü akışı en yakın taklit eden yöntemdir. Aşağıdaki model şu adımları izler:

  1. Kayıt formunu doldurur.
  2. sitekey'i data-sitekey özniteliğinden çeker.
  3. Token'ı CaptchaAI ile çözer.
  4. Gerekiyorsa data-callback fonksiyonunu tetikler.
  5. Formu gönderir ve başarı mesajını bekler.
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("test@example.com")
        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()

Testleri İşaretleyin: pytest Yapılandırması

CAPTCHA çözümü yavaş ve maliyetli olduğu için bu testleri bir işaretle (marker) ayırın. Böylece hızlı işlem hattında yalnızca gereken testleri çalıştırır, CAPTCHA çözümünü isteğe bağlı tutarsınız.

# 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)",
]
"""

Yalnızca CAPTCHA testlerini çalıştırmak için:

pytest -m captcha -v

CAPTCHA testleri olmadan hızlı bir koşu için:

pytest -m "not captcha" -v

CI/CD Maliyetini Kontrol Altında Tutma

CaptchaAI thread bazlı fiyatlandırılır: her plan, o ay boyunca thread başına sınırsız çözüm içerir; çözüm başına ücret ya da CAPTCHA türüne göre ek ücret yoktur. Yani QA maliyetinizi çözdüğünüz CAPTCHA sayısı değil, eşzamanlı kullandığınız thread sayısı belirler. Çoğu test paketi için BASIC ($15/ay, 5 thread) fazlasıyla yeterlidir ve TL dalgalanmasından bağımsız, öngörülebilir bir aylık USD gideri sağlar. Maliyeti düşük tutmak için birkaç pratik:

Strateji Faydası
Staging ortamında test edin Genelde daha düşük CAPTCHA zorluğu
CAPTCHA testlerini her push'ta değil, planlı çalıştırın Gereksiz thread kullanımını azaltır
Kararsız (flaky) testlerde sonucu önbelleğe alın Aynı çözümü tekrar tekrar istemezsiniz
Yerelde CAPTCHA adımını devre dışı bırakan bir ortam bayrağı kullanın Geliştirmede maliyet oluşmaz
CAPTCHA testlerini ayrı bir CI işinde toplayın Thread kullanımını tek yerde denetleyin

Türkiye'den Bir QA Senaryosu: Ödeme Akışını Test Etmek

Türkiye'deki geliştirici ekiplerin önemli bir kısmı e-ticaret ve fintech entegrasyonları üzerine çalışır; kayıt ve ödeme adımlarının önünde çoğu zaman reCAPTCHA v2 veya Cloudflare Turnstile bulunur. Diyelim ki bir staging ortamında staging.example.com/qa-login akışını her gece regresyondan geçiriyorsunuz. CaptchaAI bu akıştaki doğrulamayı test sırasında çözer; siz de kutucuktan ödeme onayına kadar tüm kullanıcı yolculuğunu insansız doğrularsınız.

Bir noktaya dikkat edin: test verisi olarak gerçek kişisel veri kullanmayın. Üretimden kopyalanan ya da kazınan kişisel veriler KVKK kapsamına girer. QA akışlarında test_user, +90 biçimli sahte numaralar ve tr-TR yerel ayarıyla üretilmiş kukla veri kullanmak hem mevzuata uygun hem de daha güvenlidir. CaptchaAI'yi yalnızca sahibi olduğunuz ya da test etme yetkiniz bulunan sistemlerde kullanın.


Sık Sorulan Sorular

CaptchaAI hangi CAPTCHA türlerini QA testlerinde çözebilir?

reCAPTCHA v2/v3 (Invisible ve Enterprise dâhil), Cloudflare Turnstile, Cloudflare doğrulama akışı (Challenge), GeeTest v3, BLS ve görüntü/OCR türlerini çözer. hCaptcha ile FunCaptcha desteklenmez; GeeTest v4 çok yakında geliyor. CaptchaFox, Friendly Captcha ve Lemin şu an beta aşamasındadır.

CI/CD'de CAPTCHA testlerinin maliyetini nasıl kontrol ederim?

Fiyatlandırma çözüm başına değil, thread bazlıdır — yani maliyeti eşzamanlılık belirler. CAPTCHA testlerini ayrı bir işaretle toplayıp planlı çalıştırın ve mümkünse staging ortamını tercih edin. Çoğu paket için BASIC ($15/ay, 5 thread) yeterlidir.

API anahtarımı test hattında nasıl güvende tutarım?

Anahtarı koda gömmeyin; CAPTCHAAI_API_KEY gibi bir ortam değişkeninden veya CI/CD gizli değişkenlerinden okuyun. Yukarıdaki fixture, anahtar tanımlı değilse o testi otomatik olarak devre dışı bırakır; böylece sır sızmadan pipeline yeşil kalır.

Staging sitekey'i production'dan farklı mı olur?

Genelde evet — test ortamları çoğu zaman ayrı ve daha düşük zorlukta bir reCAPTCHA sitekey'i kullanır. sitekey'i her koşuda sayfadan (data-sitekey) okuyun; sabit kodlarsanız ortam değiştiğinde testler kırılır.

CaptchaAI'yi Jest veya JUnit gibi framework'lerle kullanabilir miyim?

Evet. CaptchaAI HTTP tabanlı olduğu için dilden bağımsızdır; Jest, Mocha, JUnit, NUnit ve benzeri her test framework'üyle aynı istek/yanıt akışı üzerinden çalışır.


İlgili Kaynaklar


QA hattınızdaki gece koşularını insansız çalıştırın — CaptchaAI'yi test paketinize ekleyin.

Bu makale için yorumlar devre dışı bırakılmıştır.