クレジットを消費せずにGoのCAPTCHA連携をテストする

著者:solvethree読了時間:1分

NewClientWithBaseURL を使って、公式 Go SDK の接続先を httptest サーバーに設定します。タスクのレスポンスはサーバーが返すため、solvethree のクレジットを消費したり、アプリケーションのシークレットを渡したりせずに SDK を動作させられます。

このページの内容

ローカルフィクスチャに対して SDK を実行する

  1. 1.

    依存関係をインストールする

    Go 1.22 以降を使用してください。Go モジュール内で go get を使い、solvethree.com/[email protected] をインストールします。このモジュールは solvethree.com から配信されます。

  2. 2.

    テストを保存して実行する

    モジュール内のテスト専用ディレクトリに、例を captcha_integration_test.go として保存し、そのディレクトリで go test を実行します。フィクスチャのキー、ホスト名、プロキシは変更しないでください。これらはテストデータであり、設定が必要な認証情報やサービスではありません。

Go · 独立したSDK統合テスト
package integration_test

import (
    "context"
    "fmt"
    "net/http"
    "net/http/httptest"
    "sync/atomic"
    "testing"
    "time"
    solvethree "solvethree.com/sdk"
)

func TestSolve(t *testing.T) {
    var posts atomic.Int32
    server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        if r.Method == "POST" {
            posts.Add(1)
            fmt.Fprint(w, `{"id":"fixture-1","status":"pending"}`)
            return
        }
        fmt.Fprint(w, `{"id":"fixture-1","status":"ready","solution":{"token":"FIXTURE_TOKEN","userAgent":"fixture-browser-identity","secChUa":"fixture-hints"}}`)
    }))
    defer server.Close()
    client, err := solvethree.NewClientWithBaseURL("fixture-key", server.URL, nil)
    if err != nil { t.Fatal(err) }
    result, err := client.Solve(context.Background(), solvethree.TaskRequest{
        Site: "accounts.example.com", Action: "login", Proxy: "http://proxy.example:8080",
    }, solvethree.SolveOptions{Timeout: time.Second, PollInterval: time.Millisecond})
    if err != nil { t.Fatal(err) }
    if result.Solution.Token != "FIXTURE_TOKEN" || posts.Load() != 1 { t.Fatal("incorrect lifecycle") }
}

NewClientWithBaseURL は、テスト用にループバック HTTP を受け付けます。ここでは server.URL が本番 API アドレスの代わりとなり、ハンドラーがローカルで応答します。プロキシ値は送信されるタスクの一部にすぎず、このフィクスチャはそのプロキシに接続しません。

テストの成功で確認できること

POST レスポンスの時点では、タスクは保留中のままです。後続のリクエストでは、FIXTURE_TOKEN を含む準備完了のレスポンスを受け取ります。最後のアサーションでは、返されたトークンと POST が正確に 1 回であることの両方を確認し、このフローで誤って余分なタスクを作成していないか検出します。

ハンドラーは意図的に最小限にしています。POST 以外のすべてのリクエストに、準備完了のレスポンスを返します。ポーリングのメソッド、リクエストパス、送信された JSON は検証しません。リクエストの仕様もテストするには、想定される作成ルートとタスク取得ルートに加え、送信されたサイト、アクション、プロキシをハンドラーで確認してください。

このテストの成功は、シミュレーション上の SDK ライフサイクルが動作することを示します。実際のサイトプロファイルやプロキシ、対象によるトークンの受け入れを検証するものではありません。返されるトークンとブラウザー識別情報はフィクスチャの値です。

連携処理で判断が必要な箇所に失敗ケースを追加する

ローカルハンドラーを拡張して、アプリケーションで処理する必要がある条件を返すようにします。POST カウンターは残してください。ポーリングを再試行しても、別のタスクが作成されてはいけません。

追加のテストケース — 上記の例では検証されない範囲
追加のテストケース — 上記の例では検証されない範囲
フィクスチャの動作確認事項
ポーリングリクエストが HTTP 429、502、503、504 のいずれかを返し、その後に準備完了を返す。Solve が一時的なポーリングの失敗を再試行し、期限内で Retry-After に従い、それでも POST は 1 回しか送信しないこと。
タスクが失敗状態になり、errorCode が site-unreachable となり、エラーメッセージが含まれる。*solvethree.TaskFailedError を処理し、そのタスクのポーリングを停止してください。ErrorCode が失敗の種類を示します。Error のテキストが必要な場合は、失敗したタスクを取得してください。
作成時に成功以外の HTTP レスポンスが返される。レスポンスを成功したタスクとして扱わず、HTTP エラーを処理してください。errors.As を使って *solvethree.APIError を取り出し、StatusCode を確認します。
タスクが期限まで保留中のままになる。errors.Is で context.DeadlineExceeded を判定してください。タイムアウトは待機を停止するだけで、リモートの処理はキャンセルしません。
サーバーは作成を記録するが、クライアントがレスポンスを受信できない。*solvethree.Error の復旧情報を確認してください。CreateTask は POST を自動で再試行しません。TaskID がわかる場合は GetTask で復旧し、わからない場合は同じ RequestID と元の入力を完全にそのまま使って再送信します。

レスポンスを受信できないケースでは、テストに明示的なリクエスト ID を指定し、その ID と同じ入力が再送信されたときに既存のタスクを返すようフィクスチャを設定してください。そうしないと、復旧ではなく 2 回目の作成をテストすることになります。

最初のタスクを実行しましょう。

$5のワークスペースクレジットで始められます。

ワークスペースを作成
クレジットを消費せずにGoのCAPTCHA連携をテストする · solvethree