Sections in this lesson
Testing & Evaluation for Spring AI
Separate unit behavior, provider contracts, database retrieval and live answer quality.
Reviewed: · Content owner: Interview Preparator
What you will learn
- Build a versioned set of expected sources and abstentions.
- Test provider serialization without claiming live model quality.
- Use denied cases as release gates, not average-score offsets.
Before you start
The flow
- 1.Version cases
- 2.Run layer tests
- 3.Compare sources
- 4.Inspect failures
- 5.Decide release
Four different kinds of evidence
Unit tests replace VectorStore or ChatModel to isolate service decisions. A provider contract test uses the real Ollama adapter against a local HTTP fixture. Integration tests use a real pgvector database with deterministic model doubles. Live evaluation uses actual chosen models and labeled real questions.
Do not merge these into one claimed quality score. Passing an HTTP fixture proves serialization and parsing, not that Ollama is installed or a downloaded model answers correctly.
A small, inspectable dataset
The JSON fixture defines five cases: two tenants asking about records, a supported virtual-thread question, an unknown topic and a topic inaccessible to the second tenant. The integration test asserts exact status and source IDs from actual retrieval.
RagService tests separately reject malformed output, absent/fabricated citations, invalid input and provider failure. The tool/memory tests verify denied resources and cross-user context isolation. A regression in a denied case should block release even if common-case averages improve.
Grow toward production evaluation
Add real multilingual questions, source/claim annotations, stale-document cases and repeated runs. Record model, prompt, dataset and index versions with latency and usage. Calibrate any LLM judge against human labels; five deterministic cases are regression fixtures, not a statistical benchmark.
Try it
[ {"id":"alpha-record","tenant":"tenant-a","question":"record","status":"ANSWER","sources":["00000000-0000-0000-0000-000000000001"]}, {"id":"beta-record","tenant":"tenant-b","question":"record","status":"ANSWER","sources":["00000000-0000-0000-0000-000000000003"]}, {"id":"alpha-thread","tenant":"tenant-a","question":"virtual thread","status":"ANSWER","sources":["00000000-0000-0000-0000-000000000002"]}, {"id":"unknown","tenant":"tenant-a","question":"spaceship","status":"ABSTAIN","sources":[]}, {"id":"inaccessible","tenant":"tenant-b","question":"virtual thread","status":"ABSTAIN","sources":[]}]examples/spring-ai-lab/src/test/resources/rag-cases.json · mvn -f examples/spring-ai-lab/pom.xml -Pintegration verify. Java 21+, Spring Boot 4.0.5, Spring AI 2.0.2 where applicable. The demo uses synthetic models; live inference quality is a separate check.
Interview questions
What does the golden fixture test measure?
The expected status and retrieved source set under deterministic conditions; not general semantic quality.
Can provider fixtures replace live evaluation?
No. Adapter contracts and actual inference behavior are separate risks.
How should an access leak affect the score?
Treat it as a hard failure requiring investigation, not a small deduction in an aggregate average.
Practice
Add a Turkish query, annotate its expected source and record the real embedding model separately from fixture results.
Check your solution
- Fixture version is retained in source control.
- Denied and unknown cases are present.
- The report states which model mode ran.
Official references
Continue learning
Category sequence
Spring AI
Lesson 7 / 7
Was this lesson useful?
Change notes: Phase 2: bilingual lesson with versioned executable reference.