Testing Your App
How to test applications that use Rdakt AI
Testing applications that use Rdakt AI requires mocking or replacing the HTTP transport layer. Here are patterns for unit and integration testing.
Unit Testing with a Fake Transport
Create a fake transport that returns a predefined response:
import httpx
class FakeTransport(httpx.AsyncBaseTransport):
"""Return a fixed response for testing."""
def __init__(self, response_body: bytes, status_code: int = 200):
self.response_body = response_body
self.status_code = status_code
self.last_request: httpx.Request | None = None
async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
self.last_request = request
return httpx.Response(
status_code=self.status_code,
content=self.response_body,
headers={"content-type": "application/json"},
)Testing Anonymization
Verify that the middleware anonymizes the request before sending:
import json
from rdakt_ai import RdaktMiddleware
async def test_request_is_anonymized():
fake = FakeTransport(response_body=b'{"choices": []}')
middleware = RdaktMiddleware(inner=fake)
async with httpx.AsyncClient(transport=middleware) as client:
await client.post(
"https://api.openai.com/v1/chat/completions",
json={
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Email me at john@example.com"}],
},
)
# Inspect what was actually sent
sent_body = json.loads(fake.last_request.content)
sent_text = sent_body["messages"][0]["content"]
assert "john@example.com" not in sent_text
assert "<EMAIL_1>" in sent_textTesting Streaming Deanonymization
For streaming tests, return raw SSE bytes:
async def test_streaming_deanonymization():
sse_data = (
b'data: {"choices":[{"delta":{"content":"Hello <PERSON_1>"}}]}\n\n'
b'data: [DONE]\n\n'
)
fake = FakeTransport(
response_body=sse_data,
status_code=200,
)
# Override content-type for SSE
fake.headers = {"content-type": "text/event-stream"}
middleware = RdaktMiddleware(inner=fake, session_key="test")
# Pre-populate the session with a mapping
# ... (details depend on your session setup)Testing Detection Independently
Test the detection pipeline without the middleware:
from rdakt_ai import RdaktPipeline, DetectorStage, RegexDetector
def test_regex_detection():
pipeline = RdaktPipeline(stages=[
DetectorStage(RegexDetector()),
])
entities = pipeline.detect_sync("Contact john@example.com or call (555) 123-4567")
assert len(entities) == 2
types = {e.type for e in entities}
assert types == {"EMAIL", "PHONE"}Testing Anonymization Independently
from rdakt_ai import Anonymizer, AnonymizationStrategy, Entity, RdaktSession
def test_anonymization():
anonymizer = Anonymizer(default_strategy=AnonymizationStrategy.TOKEN)
session = RdaktSession()
entities = [Entity(value="john@example.com", type="EMAIL", start=0, end=16)]
text, mapping = anonymizer.anonymize("john@example.com", entities, session=session)
assert text == "<EMAIL_1>"
assert mapping["<EMAIL_1>"] == "john@example.com"Integration Testing
For full integration tests that hit the actual LLM API, use audit mode to verify detection without sending anonymized data:
async def test_full_integration_audit():
detected: list = []
middleware = RdaktMiddleware(
mode="audit",
on_entities_detected=lambda entities, text: detected.extend(entities),
)
client = AsyncOpenAI(
http_client=httpx.AsyncClient(transport=middleware),
)
await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "My SSN is 123-45-6789"}],
)
assert any(e.type == "SSN" for e in detected)