MedExpertMatch Testing Guide¶
Last Updated: 2026-01-20
Overview¶
This guide describes testing patterns and best practices for MedExpertMatch, with a focus on medical-specific test data considerations.
Testing Principles¶
- Test-Driven Development: Write tests first
- Integration Tests Preferred: Use Testcontainers with PostgreSQL
- Real Database: Never use H2 or in-memory databases
- Test Independence: Each test prepares its own data
Medical Test Data¶
Anonymization Requirements¶
- All patient data must be anonymized in tests
- Use synthetic test data, not real patient data
- No PHI in test fixtures or assertions
Test Data Examples¶
// Example: Anonymized medical case
MedicalCase testCase = new MedicalCase(
"case123",
"CASE-001", // Case ID (not patient ID)
"PATIENT-ANON-001", // Anonymized patient ID
"Chest pain", // Chief complaint
"Acute myocardial infarction", // Diagnosis
List.of("I21.9"), // ICD-10 codes
// ... other fields
);
Test Structure¶
Follow these testing patterns:
- Extend
BaseIntegrationTestfor database tests - Use Testcontainers for PostgreSQL
- Mock MedGemma API calls (don't call real APIs in tests)
Embedding Tests¶
Integration tests for vector embeddings:
-
EmbeddingServiceIT: Tests embedding generation (single and batch)
testGenerateEmbedding()- Single embedding generationtestGenerateEmbeddingsBatch()- Batch embedding generationtestGenerateEmbeddingAsFloatArray()- Float array formattestGenerateEmbeddingEmptyText()- Edge case handling
-
MedicalCaseRepositoryEmbeddingIT: Tests repository embedding methods
testFindWithoutEmbeddings()- Find cases needing embeddingstestUpdateEmbedding()- Update case with embeddingtestUpdateEmbeddingWithSmallerDimension()- Dimension normalizationtestFindWithoutEmbeddingsExcludesCasesWithEmbeddings()- Query correctness
-
TestDataGeneratorEmbeddingIT: Tests embedding generation in test data flow
testGenerateEmbeddings()- Standalone embedding generationtestGenerateEmbeddingsInTestDataFlow()- Integration with test data generationtestGenerateEmbeddingsHandlesEmptyCases()- Edge case handling
All embedding tests use mocked EmbeddingModel to avoid real API calls.
Vector Similarity Testing¶
Vector similarity is tested as part of SemanticGraphRetrievalService tests:
- Tests verify cosine similarity calculation using pgvector operator
<=> - Tests handle missing embeddings gracefully (return neutral score)
- Tests compare query case with doctor's historical cases
Text Input and Case Search Testing¶
MedicalAgentController Tests¶
File: MedicalAgentControllerIT.java
Tests for the matchFromText endpoint:
-
testMatchFromText_WithRequiredCaseText()- Tests basic text input with only requiredcaseTextparameter- Verifies case creation with correct chief complaint
- Verifies default case type (INPATIENT)
- Verifies case is persisted to database
-
testMatchFromText_WithAllOptionalParameters()- Tests text input with all optional parameters- Verifies
symptoms,additionalNotes,patientAge,caseTypeare saved correctly - Verifies all parameters are persisted
- Verifies
-
testMatchFromText_Validation_MissingCaseText()- Tests validation error whencaseTextis missing- Verifies
IllegalArgumentExceptionis thrown
- Verifies
-
testMatchFromText_Validation_EmptyCaseText()- Tests validation error whencaseTextis empty- Verifies
IllegalArgumentExceptionis thrown with appropriate message
- Verifies
-
testMatchFromText_WithInvalidCaseType()- Tests that invalidcaseTypedefaults to INPATIENT- Verifies graceful handling of invalid enum values
-
testMatchFromText_WithDifferentCaseTypes()- Tests SECOND_OPINION and CONSULT_REQUEST case types- Verifies all case types are handled correctly
MedicalCaseRepository Search Tests¶
File: MedicalCaseRepositoryIT.java
Tests for the search() method:
-
testSearch_ByQuery()- Tests text search in chiefComplaint, symptoms, additionalNotes- Verifies case-insensitive search
- Verifies partial matching
-
testSearch_BySpecialty()- Tests filtering by required specialty- Verifies exact match filtering
-
testSearch_ByUrgencyLevel()- Tests filtering by urgency level- Verifies enum value filtering
-
testSearch_WithAllFilters()- Tests combined filters (query + specialty + urgency)- Verifies all filters work together
- Verifies no results when filters don't match
-
testSearch_WithMaxResults()- Tests result limiting- Verifies
LIMITclause works correctly
- Verifies
-
testSearch_EmptyQuery()- Tests null/empty query handling- Verifies all cases returned when query is null/empty
-
testSearch_CaseInsensitive()- Tests case-insensitive search- Verifies
ILIKEoperator works correctly
- Verifies
-
testSearch_PartialMatch()- Tests partial text matching- Verifies substring matching in multiple fields
-
testSearch_OrderByCreatedAt()- Tests result ordering- Verifies results ordered by
created_at DESC(most recent first)
- Verifies results ordered by
MatchController Tests¶
File: MatchControllerIT.java
Tests for the case search endpoint (GET /api/cases/search):
testSearchCases_ByQuery()- Tests text search via REST endpointtestSearchCases_BySpecialty()- Tests specialty filtering via REST endpointtestSearchCases_ByUrgencyLevel()- Tests urgency level filtering via REST endpointtestSearchCases_WithAllFilters()- Tests combined filters via REST endpointtestSearchCases_WithMaxResults()- Tests result limiting via REST endpointtestSearchCases_EmptyQuery()- Tests null/empty query handling via REST endpointtestSearchCases_CaseInsensitive()- Tests case-insensitive search via REST endpointtestSearchCases_DefaultMaxResults()- Tests default maxResults parameter
All tests follow TDD principles and use Testcontainers with PostgreSQL.
Related Documentation¶
- Development Guide
- Architecture
- Synthetic Data Generator - Comprehensive feature description including vector embeddings
- Find Specialist Flow - Text input endpoint and case search documentation
Last updated: 2026-01-20